shiro中JdbcRealm使用salt的问题

 

JdbcRealm中创建用户的一般写法:

public String register(User user) {
        RandomNumberGenerator gen = new SecureRandomNumberGenerator();
        ByteSource salt = gen.nextBytes();

        String hashedPasswordBase64 = new Sha256Hash(user.getPassword(), salt, 1024).toBase64();

        user.setPassword(hashedPasswordBase64);
        user.setSalt(salt.getBytes());

        try {
            userDAO.create(user);
        } catch (SQLException e) {
            e.printStackTrace();
            //TOOD:log error
        }
        return "redirect:login";
    }

这个里面一个比较麻烦的问题在于salt该如何存放。nextBytes()方法返回的实际值是SimpleByteSource,有些地方直接使用salt.toString()存作字符串,SimpleByteSource重写了toString方法,实际上返回的是base64编码。问题在于Jdbc并不能使用这种方式存放的数据。

 

看下JdbcRealm的doGetAuthenticationInfo方法:

protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

        UsernamePasswordToken upToken = (UsernamePasswordToken) token;
        String username = upToken.getUsername();

        // Null username is invalid
        if (username == null) {
            throw new AccountException("Null usernames are not allowed by this realm.");
        }

        Connection conn = null;
        SimpleAuthenticationInfo info = null;
        try {
            conn = dataSource.getConnection();

            String password = null;
            String salt = null;
            switch (saltStyle) {
            case NO_SALT:
                password = getPasswordForUser(conn, username)[0];
                break;
            case CRYPT:
                // TODO: separate password and hash from getPasswordForUser[0]
                throw new ConfigurationException("Not implemented yet");
                //break;
            case COLUMN:
                String[] queryResults = getPasswordForUser(conn, username);
                password = queryResults[0];
                salt = queryResults[1];
                break;
            case EXTERNAL:
                password = getPasswordForUser(conn, username)[0];
                salt = getSaltForUser(username);
            }

            if (password == null) {
                throw new UnknownAccountException("No account found for user [" + username + "]");
            }

            info = new SimpleAuthenticationInfo(username, password.toCharArray(), getName());

            if (salt != null) {
                info.setCredentialsSalt(ByteSource.Util.bytes(salt));
            }

        } catch (SQLException e) {
            final String message = "There was a SQL error while authenticating user [" + username + "]";
            if (log.isErrorEnabled()) {
                log.error(message, e);
            }

            // Rethrow any SQL errors as an authentication exception
            throw new AuthenticationException(message, e);
        } finally {
            JdbcUtils.closeConnection(conn);
        }

        return info;
    }

可以看出JdbcRealm是吧密码和盐都当作字符串读取,而ByteSource本质上存放的是byte数组。深究下去,实际上是使用UTF-8解码字符串得到了byte[]。但问题在于,String并不是什么byte都可以存放的,不论是JVM内部使用的UTF-16,还是这里编解码使用的UTF-8,都是有一定格式要求的。不是什么byte[]都可以放进去然后原封不动的拿出来,更何况中间还经过了一次MySQL。

更重要的是,根本没有必要使用字符串存放,ByteSource.Util.bytes本身就有byte[]的重载,而base64也谈不上什么加密。直接存放二进制是不存在问题的。实现起来也很简单。重写doGetAuthenticationInfo,使用byte[]创建SimpleByteSource即可。

时间: 2024-12-19 22:22:44

shiro中JdbcRealm使用salt的问题的相关文章

从零到实现Shiro中Authorization和Authentication的缓存

本文大纲 一.简介 二.缓存的概念 三.自定义实现缓存机制 四.什么是Ehcache 五.Ehcache怎么用 六.Spring对缓存的支持 七.Spring+Ehcache实现 八.Spring+Shiro+Ehcache实现 九.总结 一.简介 在项目中,用到Shiro来做验证授权的控制.但在实际使用的时候,发现用户每访问一个功能,都会重新到UserRealm中获取一次权限.这样子会花费大量的系统系统.此时就想到了使用缓存,查了一下,Shiro也确实支持Authorization和Authe

shiro中的reaml理解及实现机制

shiro中的reaml非常重要,所有的身份数据验证都在reaml中实现.可以把Realm看成DataSource,即安全数据源. Shiro从Realm获取安全数据(如用户.角色.权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法: 也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作. 下面以例子讲解其实现机制: 最开始用户.角色.权限都配置在shiro.ini配置文件中. 但实际项目中更多的是保存数

shiro中CacheManager相关的类结构介绍,提供redis Cache实现

cacheManager主要用于对shiro中的session.realm中的认证信息.授权信息进行缓存. 1.类结构 2.接口及类介绍 CacheManager 提供根据名字获取cache的作用. AbstractCacheManager 本地提供并发map做缓存.提供抽象类给子类继承,子类只需要创建cache即可. MemoryConstrainedCacheManager 实现上面的抽象类.创建一个map作为缓存. 3.Cache相关介绍 Cache接口 主要提供缓存相关的增删改查方法.

Shiro中的Rememberme后出现浏览器500错误

问题详述:在Shiro中添加Remember me功能后,只要勾选Remember me选项为true的时候,浏览器就会跳转到一个不可达页面,并且在Chrome中显示HTTP 500错误. 问题追踪: 1. 设置Shiro的日志权限级别为DEBUG log4j设置 # Default Shiro logging log4j.logger.org.apache.shiro=DEBUG 2.点击登录按钮,查看日志输入: DEBUG - Authentication successful for to

项目一:第十三天 1、菜单数据管理 2、权限数据管理 3、角色数据管理 4、用户数据管理 5、在realm中动态查询用户权限,角色 6、Shiro中整合ehcache缓存权限数据

1 课程计划 菜单数据管理 权限数据管理 角色数据管理 用户数据管理 在realm中动态查询用户权限,角色 Shiro中整合ehcache缓存权限数据         2 菜单数据添加 2.1 使用combotree父菜单项数据     1. 页面:menu_add.jsp 2. 修改组件样式:easyui-combotree,修改url  树型表格treeGrid跟下来数combotree要求数据格式基本一致. Combotree通过text属性展示文本.   3. 使用treegrid组件的

jsp输出shiro中session信息

一.引用shiro标签 jsp页面头部引用<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>标签 二.shiro中存放的是用户名等字符串: <shiro:principal/> 三.shiro中存放的是用户对象,property是对象里面的属性,相当于user.getUserName() <shiro:principal property="userN

Shiro权限管理框架(三):Shiro中权限过滤器的初始化流程和实现原理

本篇是Shiro系列第三篇,Shiro中的过滤器初始化流程和实现原理.Shiro基于URL的权限控制是通过Filter实现的,本篇从我们注入的ShiroFilterFactoryBean开始入手,翻看源码追寻Shiro中的过滤器的实现原理. 初始化流程 ShiroFilterFactoryBean实现了FactoryBean接口,那么Spring在初始化的时候必然会调用ShiroFilterFactoryBean的getObject()获取实例,而ShiroFilterFactoryBean也在

shiro之 JdbcRealm及Authentication Strategy

1. 使用shiro框架来完成认证工作,默认情况下使用的是lniRealm.如果需要使用其他Realm,那么需要进行相关的配置. 2.lni 配置文件讲解:[main]section是你配置应用程序的SecurityManager实例及任何它的依赖组件(如:Realms)的地方. [main] myRealm=cn.sxt.realm.MyRealm #依赖注入 securityManager.realm=$myRealm [users]section 允许你定义一组静态的用户账户.这在大部分拥

shiro中unauthorizedUrl不起作用

解决方法: 在shiro配置文件中添加(异常全路径做key,错误页面做value) <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="exceptionMappings"> <props> <prop key="org.apache.shiro.authz.Una