最近在做一个springBoot集成mybatis与shiro的Demo 但是遇到shiro验证用户名密码一直提示不正确,实在是搞不明白,demo奉上http://pan.baidu.com/s/1jI3m9ZC,望解答,谢谢。
简单的对你的代码修改了下,以下贴出:
1.首先你的ShiroAction.userLogin,补货异常,不是你那么使用的。
@RestController
public class ShiroAction {
private static final Logger logger = LoggerFactory.getLogger(ShiroAction.class);
/**
*
* @Title: userLogin
* @Description: 用户登录
* @return
*/
@RequestMapping(value="/login",method=RequestMethod.POST)
public String userLogin(HttpServletRequest request,String username, String password, Map<String, Object> map) {
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
Subject subject = SecurityUtils.getSubject();
String msg=null;
try {
logger.info("对用户[" + username + "]进行登录验证..验证开始");
subject.login(token);
logger.info("对用户[" + username + "]进行登录验证..验证通过");
}catch(UnknownAccountException uae){
logger.info("对用户[" + username + "]进行登录验证..验证未通过,未知账户");
msg = "未知账户";
}catch(IncorrectCredentialsException ice){
logger.info("对用户[" + username + "]进行登录验证..验证未通过,错误的凭证");
msg = "密码不正确";
}catch(LockedAccountException lae){
logger.info("对用户[" + username + "]进行登录验证..验证未通过,账户已锁定");
msg = "账户已锁定";
}catch(ExcessiveAttemptsException eae){
logger.info("对用户[" + username + "]进行登录验证..验证未通过,错误次数过多");
msg = "用户名或密码错误次数过多";
}catch(AuthenticationException ae){
//通过处理Shiro的运行时AuthenticationException就可以控制用户登录失败或密码错误时的情景
logger.info("对用户[" + username + "]进行登录验证..验证未通过,堆栈轨迹如下");
ae.printStackTrace();
msg = "用户名或密码不正确";
}
map.put("msg", msg);
//验证是否登录成功
if(subject.isAuthenticated()){
logger.info("用户[" + username + "]登录认证通过(这里可以进行一些认证通过后的一些系统参数初始化操作)");
return "/login";
}else{
token.clear();
return "/login";
}
}
}
MyRealm.中的验证代码:
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("使用了自定义的realm,用户认证...");
System.out.println("用户名:" + ((UsernamePasswordToken) token).getUsername());
System.out.println("密码:" + new String(((UsernamePasswordToken) token).getPassword()));
// 获取用户名
String userName = (String) token.getPrincipal();
// 依据用户名去数据库查询
// 查询到了数据,验证密码是否正确
// 密码正确,认证通过
// 密码错误,认证失败
// 没有查询到数据,认证失败
sysUser su = new sysUser();
su.setLoginName(userName);
su = sysUserserviceImpl.selectByPrimaryKey(su);
SimpleAuthenticationInfo SimpleAuthenticationInfo = new SimpleAuthenticationInfo(su.getLoginName(), su.getPassword(), this.getName());
return SimpleAuthenticationInfo;
}
最后,最关键的一点,你的密码明文传输到shiro,并未使用加密处理,但是数据库中的密码却使用了加密,修改方法,就是在ShiroAction的UsernamePasswordToken生成之前对密码加密,当然,靠谱的是在前端就加密处理;
我在你这个例子上面,密码框直接贴数据库加密后的串,点击登陆:
以下是执行日志:
2017-11-01 13:34:26.224 INFO 11232 --- [nio-8080-exec-9] com.kfit.zzy.controller.ShiroAction : 对用户[admin]进行登录验证..验证开始
使用了自定义的realm,用户认证...
用户名:admin
密码:d3c59d25033dbf980d29554025c23a75
2017-11-01 13:34:26.228 INFO 11232 --- [nio-8080-exec-9] com.kfit.zzy.controller.ShiroAction : 对用户[admin]进行登录验证..验证通过
2017-11-01 13:34:26.228 INFO 11232 --- [nio-8080-exec-9] com.kfit.zzy.controller.ShiroAction : 用户[admin]登录认证通过(这里可以进行一些认证通过后的一些系统参数初始化操作)
在ShiroFilterFactoryBean加上一下代码就可以了
@Bean
public SecurityManager securityManager(){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//设置realm.
securityManager.setRealm(myShiroRealm());
//注入缓存管理器;
securityManager.setCacheManager(ehCacheManager());//这个如果执行多次,也是同样的一个对象;
//注入记住我管理器;
//securityManager.setRememberMeManager(rememberMeManager());
return securityManager;
}
/**
* 身份认证realm;
* (这个需要自己写,账号密码校验;权限等)
* @return
*/
@Bean
public MyShiroRealm myShiroRealm(){
MyShiroRealm myShiroRealm = new MyShiroRealm();
myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());;
return myShiroRealm;
}
/**
* shiro缓存管理器;
* 需要注入对应的其它的实体类中:
* 1、安全管理器:securityManager
* 可见securityManager是整个shiro的核心;
* @return
*/
@Bean
public EhCacheManager ehCacheManager(){
System.out.println("ShiroConfiguration.getEhCacheManager()");
EhCacheManager cacheManager = new EhCacheManager();
cacheManager.setCacheManagerConfigFile("classpath:config/ehcache-shiro.xml");
return cacheManager;
}
/**
* 凭证匹配器
* (由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了
* 所以我们需要修改下doGetAuthenticationInfo中的代码;
* )
* @return
*/
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher(){
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
hashedCredentialsMatcher.setHashAlgorithmName("md5");//散列算法:这里使用MD5算法;
hashedCredentialsMatcher.setHashIterations(2);//散列的次数,比如散列两次,相当于 md5(md5(""));
return hashedCredentialsMatcher;
}