目录
出现的问题
我的解决思路
出现的问题
在shiro控制下在进行登陆时出现报错
[Submitted credentials for token [org.apache.shiro.authc.UsernamePasswordToken - 1300, rememberMe=false] did not match the expected credentials.]
报错是因为 密码不匹配
这个不匹配的原因是在前端获得的密码与数据库获得的加密密码 进行对比 出现异常。
正常情况下:
从UserRealm类(我自定义的ShiroRealm)中对于对比开始时开始传入数据。

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

再到 对比数据

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

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

所以我的问题是在于从数据库中存储好的密码就不是正确加密的,或者加密的方式和在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);
*/
}到这里才发现其实是我的盐 的本身的数据出错导致的。
本来是用用户名来做盐;结果后来是生成的盐,再去做了一次盐的方法。导致算出来的盐是不符合最开始认证的参数的。导致报错密码不匹配
所以 需要注意在进行存储时 一定要核对盐的本身数据和认证的流程是否有问题。否则出现我这类的报错。
以上。
















