思路
在使用shiro的时候,我们需要将ShiroConfiguration注入到spring中和实现MyShiroRealm
在ShiroConfiguration中 主要作用是
权限过滤规则
管理器注入(缓存、记住我等管理器)
密码匹配器
在使用密码匹配时,我们需要告诉shiro使用什么规则(MD5)
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher(){
// HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
HashedCredentialsMatcher hashedCredentialsMatcher = new RetryLimitHashedCredentialsMatcher(ehCacheManager());
hashedCredentialsMatcher.setHashAlgorithmName("md5");//散列算法:这里使用MD5算法;
hashedCredentialsMatcher.setHashIterations(2);//散列的次数,比如散列两次,相当于 md5(md5(""));
return hashedCredentialsMatcher;
}
在Realm中
我们把正确的账号密码告诉shiro,shiro就会使用我们之前确定的规则进行匹配。
//明文: 若存在,将此用户存放到登录认证info中,无需自己做密码对比,Shiro会为我们进行密码对比校验
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
userInfo, //用户名
userInfo.getPassword(), //密码
getName() //realm name
);
第一个参数是放在subject中,可以在其他功能里使用。
Subject subject = SecurityUtils.getSubject();//当前会话
if( subject.isAuthenticated()){
UserInfo userInfo=(UserInfo) subject.getPrincipal();
setFieldValByName("editor", userInfo.getUserName(), metaObject);
}
第二个参数是正确的密码,在我们new SimpleAuthenticationInfo时 会调用HashedCredentialsMatcher里的doCredentialsMatch方法。在我们传过来的密码 会自动帮我们MD5加密后与我们查询到的正确密码匹配。
第三个参数。是realm的名字。
在使用注解时,@RequiresRoles 是否拥有角色。
就是在MyShiroRealm中重写的doGetAuthorizationInfo里设置的角色。
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
UserInfo userInfo = (UserInfo)principals.getPrimaryPrincipal();
for(SysRole role:userInfo.getRoleList()){
authorizationInfo.addRole(role.getRole());//添加角色
SysRole sysRole = sysRoleService.selectRoleByIdWithPermission(role.getId());//获取角色
for(SysPermission p:sysRole.getPermissions()){
authorizationInfo.addStringPermission(p.getPermission());//添加权限
}
}
//属于user角色
@RequiresRoles("user")
//必须同时属于user和admin角色
@RequiresRoles({"user","admin"})
//属于user或者admin之一;修改logical为OR 即可
@RequiresRoles(value={"user","admin"},logical=Logical.OR)使用注解
@RequiresPermissions(“userInfo:del”)是否拥有权限
//符合index:hello权限要求
@RequiresPermissions("index:hello")
//必须同时复核index:hello和index:world权限要求
@RequiresPermissions({"index:hello","index:world"})
//符合index:hello或index:world权限要求即可
@RequiresPermissions(value={"index:hello","index:world"},logical=Logical.OR)
附上一个连接注解详细连接http://blog.youkuaiyun.com/w_stronger/article/details/73109248
在实现AuthorizingRealm时,
我们需要doGetAuthenticationInfo做认证和doGetAuthorizationInfo权限信息
这两个接口实现就可以。
在我们登录的时候 首先会跑doGetAuthenticationInfo这个方法。
做完密码匹配后 会将结果放到request中 存放一个参数shiroLoginFailure。
如果失败后我们通过判断异常就可以知道是什么登录错误
// 登录提交地址和applicationontext-shiro.xml配置的loginurl一致。 (配置文件方式的说法)
@RequestMapping(value="/login",method=RequestMethod.POST)
public String login(HttpServletRequest request, Map<String, Object> map) throws Exception {
System.out.println("HomeController.login()");
// 登录失败从request中获取shiro处理的异常信息。
// shiroLoginFailure:就是shiro异常类的全类名.
String exception = (String) request.getAttribute("shiroLoginFailure");
System.out.println("exception=" + exception);
String msg = "";
if (exception != null) {
if (UnknownAccountException.class.getName().equals(exception)) {
System.out.println("UnknownAccountException -- > 账号不存在:");
msg = "UnknownAccountException -- > 账号不存在:";
} else if (IncorrectCredentialsException.class.getName().equals(exception)) {
System.out.println("IncorrectCredentialsException -- > 密码不正确:");
msg = "IncorrectCredentialsException -- > 密码不正确:";
} else if ("kaptchaValidateFailed".equals(exception)) {
System.out.println("kaptchaValidateFailed -- > 验证码错误");
msg = "kaptchaValidateFailed -- > 验证码错误";
}else if (ExcessiveAttemptsException.class.getName().equals(exception)) {
System.out.println("ExcessiveAttemptsException -- > 登录失败次数过多:");
msg = "ExcessiveAttemptsException -- > 登录失败次数过多:";
} else {
msg = "else >> "+exception;
System.out.println("else -- >" + exception);
}
}
map.put("msg", msg);
// 此方法不处理登录成功,由shiro进行处理.
return "/login";
}