目录

出现的问题

我的解决思路


出现的问题

在shiro控制下在进行登陆时出现报错

 [Submitted credentials for token [org.apache.shiro.authc.UsernamePasswordToken - 1300, rememberMe=false] did not match the expected credentials.] 

报错是因为 密码不匹配

这个不匹配的原因是在前端获得的密码与数据库获得的加密密码 进行对比 出现异常。

正常情况下:

从UserRealm类(我自定义的ShiroRealm)中对于对比开始时开始传入数据。

MDT 的rules取computername mdt invalid credentials_数据

验证token 和 info 两个数据是否为空

MDT 的rules取computername mdt invalid credentials_shiro_02

再到 对比数据

MDT 的rules取computername mdt invalid credentials_md5_03

最后是看到token信息和info的hash对比

MDT 的rules取computername mdt invalid credentials_java_04

但是报错 token的hash 和 account的不一致

MDT 的rules取computername mdt invalid credentials_spring boot_05

所以我的问题是在于从数据库中存储好的密码就不是正确加密的,或者加密的方式和在userRelam中配置的不一致

 

我的解决思路

第一步 重新确认 SiroConfigure中 对 密码验证模块的代码是否正确。 配置时MD5 算法、散列次数为2,以及配置加密编码是16进制。

/**
     * 凭证匹配器
     * 密码校验规则HashedCredentialsMatcher
     * 这个类是为了对密码进行编码的 ,
     * 防止密码在数据库里明码保存 , 当然在登陆认证的时候 ,
     * 这个类也负责对form里输入的密码进行编码
     * 处理认证匹配处理器:如果自定义需要实现继承HashedCredentialsMatcher
     * @return
     */
    @Bean(name="hashedCredentialsMatcher")
    public HashedCredentialsMatcher hashedCredentialsMatcher(){
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();

        hashedCredentialsMatcher.setHashAlgorithmName("MD5");//散列算法:这里使用MD5算法;
        hashedCredentialsMatcher.setHashIterations(2);//散列的次数

        //storedCredentialsHexEncoded默认是true,此时用的是密码加密用的是Hex编码;false时用Base64编码
        hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);
        return hashedCredentialsMatcher;
    }

 

第二步是在自定义的ShiroRealm中的信息配置情况

仅针对于认证的方法如下:在重写的doGetAuthenticationInfo 方法中 加盐的是通过用户的名称来生成的。

/**
     * 认证
     *
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {


//        System.out.println("用户进行登入操作 subject.login(token) 以后会进入UserRealm 的 doGetAuthenticationInfo(方法中)");

        String username = (String) authenticationToken.getPrincipal(); //传递过来的username 就是登陆的用户名称

        User user = userMapper.queryInfoByName(username);

        if (user == null) {
            logger.debug("登录用户不存在...");
            throw new AuthenticationException("用户不存在");
        }
        ("开始处理异地登录");
        //这里是处理某处登陆后,当前登录失效的方法,就像异地登录那样
        Collection<Session> sessions = sessionDAO.getActiveSessions();
        for (Session session : sessions) {
            String loginedUserName = String.valueOf(session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY));
            if (username.equals(loginedUserName)) {
                //说明已经是登陆成功的了。需要挤掉
                session.setTimeout(0L);
                break;
            }
        }

        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo( user, user.getPassword(),
               ByteSource.Util.bytes(user.getUsername()),  // 加盐后的密码
               getName()); // 指定当前 Realm 的类名
        return authenticationInfo;
    }

第三步:对shiroConfigure中进行配置Bean 并且 对加盐的匹配器进行注册。

@Bean(name = "securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(UserRealm userRealm) {
        DefaultWebSecurityManager dwsm = new DefaultWebSecurityManager();
        dwsm.setRealm(userRealm);
        // <!-- 用户授权/认证信息Cache, 采用EhCache 缓存 -->
        dwsm.setCacheManager(getEhCacheManager());
        dwsm.setSessionManager(getDefaultWebSessionManager());
        return dwsm;
    }

    @Bean
    public UserRealm userRealm(EhCacheManager cacheManager) {
        UserRealm userRealm = new UserRealm();
        userRealm.setCacheManager(cacheManager);
        /*凭证匹配器 加盐 */
        userRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return userRealm;
    }

 

    // 开启shrio注解支持  可以不用 @Component
    @Bean
    public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(UserRealm userRealm) { // 使用的UserRealm
        AuthorizationAttributeSourceAdvisor aasa = new AuthorizationAttributeSourceAdvisor();
        aasa.setSecurityManager(getDefaultWebSecurityManager(userRealm));
        return aasa;
    }

第四步:在登陆模块进行数据传递

//省略的代码
        ("接收到user:" + user);
        //这里是将得到的用户和密码放到token中

        Subject subject = SecurityUtils.getSubject();
        
        String password = user.getPassword();
        //存入前端上传的代码
        UsernamePasswordToken usernamePasswordToken = new   UsernamePasswordToken(user.getUsername(), password);
        try {
            subject.login(usernamePasswordToken);
            subject.getSession().setAttribute("session", user);
        } catch (AuthenticationException authenticationException) {
            logger.error(authenticationException.getMessage());
            Result result = new Result();
            result.setCode(StatusConfig.NO_FOUND_STATUS);
            result.setMessage("用户密码不匹配!");
            return result;

        }
//省略的代码

 

到这里为止 我的步骤应该是没错的。

现在需要验证我在注册时的加密方式是否正确。 通过以下方式来实现密码加盐。 配置的方式和次数与配置器中的一致。说明没有问题。

/**
     * 密码加盐
     *
     * @param password 原密码
     * @param salt     用用户名作为盐 在进行运算
     * @return
     */
    public static final String md5(String password, String salt) {
        //加密方式
        String hashAlgorithmName = "md5";
        //盐:为了即使相同的密码不同的盐加密后的结果也不同
        ByteSource byteSalt = ByteSource.Util.bytes(salt);
        //密码
        Object source = password;
        //加密次数
        int hashIterations = 2;
        SimpleHash result = new SimpleHash(hashAlgorithmName, source, byteSalt, hashIterations);
        return result.toString();
    }

只能看最后一步,在生成密码时是否有问题

目前我通过 test方式注入到数据库 

@Autowired
    private UserMapper userMapper;

    @Test
    public void insertTest() {

        String password = "shuaiqiergou";
        String username = "ergou";

        //到这里都是正确的
        String md5Password = MD5Utils.md5(password, username);
        
        //以下开始错误了
      /* ByteSource bytes = ByteSource.Util.bytes(username);

        String salt = bytes.toString();
        md5Password = MD5Utils.md5(password, salt);
       */

    }

 到这里才发现其实是我的盐 的本身的数据出错导致的。

本来是用用户名来做盐;结果后来是生成的盐,再去做了一次盐的方法。导致算出来的盐是不符合最开始认证的参数的。导致报错密码不匹配

所以 需要注意在进行存储时 一定要核对盐的本身数据和认证的流程是否有问题。否则出现我这类的报错。

以上。