1.取消原springmvc认证和授权拦截器
去掉springmvc.xml中配置的LoginInterceptor和PermissionInterceptor拦截器。
2.web.xml添加shiro Filter
shiroFilter org.springframework.web.filter.DelegatingFilterProxy targetFilterLifecycle true targetBeanName shiroFilter shiroFilter /*
3.applicationContext-shiro.xml
/logout.action = logout /refuse.jsp = anon /item/list.action = roles[item],authc /js/** anon /images/** anon /styles/** anon /validatecode.jsp anon /item/* authc /** = authc
securityManager:这个属性是必须的。
loginUrl:没有登录认证的用户请求将跳转到此地址进行认证,不是必须的属性,不输入地址的话会自动寻找项目web项目的根目录下的”/login.jsp”页面。
unauthorizedUrl:没有权限默认跳转的页面。
4.自定义realm
此realm先不从数据库查询权限数据,当前需要先将shiro整合完成,在上边章节定义的realm基础上修改。
public class CustomRealm1 extends AuthorizingRealm { @Override public String getName() { return "customRealm"; } // 支持什么类型的token @Override public boolean supports(AuthenticationToken token) { return token instanceof UsernamePasswordToken; } // 认证 @Override protected AuthenticationInfo doGetAuthenticationInfo( AuthenticationToken token) throws AuthenticationException { // 从token中 获取用户身份信息 String username = (String) token.getPrincipal(); // 拿username从数据库中查询 // .... // 如果查询不到则返回null if (!username.equals("zhang")) { // 这里模拟查询不到 return null; } // 获取从数据库查询出来的用户密码 String password = "123";// 这里使用静态数据模拟。。 // 根据用户id从数据库取出菜单 //...先用静态数据 Listmenus = new ArrayList ();; SysPermission sysPermission_1 = new SysPermission(); sysPermission_1.setName("商品管理"); sysPermission_1.setUrl("/item/queryItem.action"); SysPermission sysPermission_2 = new SysPermission(); sysPermission_2.setName("用户管理"); sysPermission_2.setUrl("/user/query.action"); menus.add(sysPermission_1); menus.add(sysPermission_2); // 构建用户身份信息 ActiveUser activeUser = new ActiveUser(); activeUser.setUserid(username); activeUser.setUsername(username); activeUser.setUsercode(username); activeUser.setMenus(menus); // 返回认证信息由父类AuthenticatingRealm进行认证 SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo( activeUser, password, getName()); return simpleAuthenticationInfo; } // 授权 @Override protected AuthorizationInfo doGetAuthorizationInfo( PrincipalCollection principals) { // 获取身份信息 ActiveUser activeUser = (ActiveUser) principals.getPrimaryPrincipal(); //用户id String userid = activeUser.getUserid(); // 根据用户id从数据库中查询权限数据 // ....这里使用静态数据模拟 List permissions = new ArrayList (); permissions.add("item:query"); permissions.add("item:update"); // 将权限信息封闭为AuthorizationInfo SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); for (String permission : permissions) { simpleAuthorizationInfo.addStringPermission(permission); } return simpleAuthorizationInfo; }}
5.登录
// 用户登陆提交 @RequestMapping("/login") public String loginsubmit(Model model, HttpServletRequest request) throws Exception { // shiro在认证过程中出现错误后将异常类路径通过request返回 String exceptionClassName = (String) request .getAttribute("shiroLoginFailure"); if(exceptionClassName!=null){ if (UnknownAccountException.class.getName().equals(exceptionClassName)) { throw new CustomException("账号不存在"); } else if (IncorrectCredentialsException.class.getName().equals( exceptionClassName)) { throw new CustomException("用户名/密码错误"); } else if("randomCodeError".equals(exceptionClassName)){ throw new CustomException("验证码错误"); } else{ throw new Exception();//最终在异常处理器生成未知错误 } } return "login"; }
6.首页
由于session由shiro管理,需要修改首页的controller方法,将session中的数据通过model传到页面。
//系统首页 @RequestMapping("/first") public String first(Model model)throws Exception{ //主体 Subject subject = SecurityUtils.getSubject(); //身份 ActiveUser activeUser = (ActiveUser) subject.getPrincipal(); model.addAttribute("activeUser", activeUser); return "/first"; }
7.退出
由于使用shiro的sessionManager,不用开发退出功能,使用shiro的logout拦截器即可。
/logout.action = logout
8.无权限refuse.jsp
当用户无操作权限,shiro将跳转到refuse.jsp页面。