三、回顾URL拦截
我们在学习的路途上也是使用过几次URL对权限进行拦截的
当时我们做了权限的增删该查的管理系统,但是在权限表中是没有把资源添加进去,我们使用的是Map集合来进行替代的。
http://blog.csdn.net/hon_3y/article/details/61926175
随后,我们学习了动态代理和注解,我们也做了一个基于注解的拦截
- 在Controller得到service对象的时候,service工厂返回的是一个动态代理对象回去
- Controller拿着代理对象去调用方法,代理对象就会去解析该方法上是否有注解
- 如果有注解,那么就需要我们进行判断该主体是否认证了,如果认证了就判断该主体是否有权限
- 当我们解析出该主体的权限和我们注解的权限是一致的时候,才放行!
http://blog.csdn.net/hon_3y/article/details/70767050
流程:
这里写图片描述
3.1认证的JavaBean
我们之前认证都是放在默认的Javabean对象上的,现在既然我们准备学Shiro了,我们就得专业一点,弄一个专门存储认证信息的JavaBean
/** * 用户身份信息,存入session 由于tomcat将session会序列化在本地硬盘上,所以使用Serializable接口 * * @author Thinkpad * */ public class ActiveUser implements java.io.Serializable { private String userid;//用户id(主键) private String usercode;// 用户账号 private String username;// 用户名称 private List<SysPermission> menus;// 菜单 private List<SysPermission> permissions;// 权限 public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getUsercode() { return usercode; } public void setUsercode(String usercode) { this.usercode = usercode; } public String getUserid() { return userid; } public void setUserid(String userid) { this.userid = userid; } public List<SysPermission> getMenus() { return menus; } public void setMenus(List<SysPermission> menus) { this.menus = menus; } public List<SysPermission> getPermissions() { return permissions; } public void setPermissions(List<SysPermission> permissions) { this.permissions = permissions; } }
认证的服务
@Override public ActiveUser authenticat(String userCode, String password) throws Exception { /** 认证过程: 根据用户身份(账号)查询数据库,如果查询不到用户不存在 对输入的密码 和数据库密码 进行比对,如果一致,认证通过 */ //根据用户账号查询数据库 SysUser sysUser = this.findSysUserByUserCode(userCode); if(sysUser == null){ //抛出异常 throw new CustomException("用户账号不存在"); } //数据库密码 (md5密码 ) String password_db = sysUser.getPassword(); //对输入的密码 和数据库密码 进行比对,如果一致,认证通过 //对页面输入的密码 进行md5加密 String password_input_md5 = new MD5().getMD5ofStr(password); if(!password_input_md5.equalsIgnoreCase(password_db)){ //抛出异常 throw new CustomException("用户名或密码 错误"); } //得到用户id String userid = sysUser.getId(); //根据用户id查询菜单 List<SysPermission> menus =this.findMenuListByUserId(userid); //根据用户id查询权限url List<SysPermission> permissions = this.findPermissionListByUserId(userid); //认证通过,返回用户身份信息 ActiveUser activeUser = new ActiveUser(); activeUser.setUserid(sysUser.getId()); activeUser.setUsercode(userCode); activeUser.setUsername(sysUser.getUsername());//用户名称 //放入权限范围的菜单和url activeUser.setMenus(menus); activeUser.setPermissions(permissions); return activeUser; }
Controller处理认证,如果身份认证成功,那么把认证信息存储在Session中
@RequestMapping("/login") public String login(HttpSession session, String randomcode,String usercode,String password)throws Exception{ //校验验证码,防止恶性攻击 //从session获取正确验证码 String validateCode = (String) session.getAttribute("validateCode"); //输入的验证和session中的验证进行对比 if(!randomcode.equals(validateCode)){ //抛出异常 throw new CustomException("验证码输入错误"); } //调用service校验用户账号和密码的正确性 ActiveUser activeUser = sysService.authenticat(usercode, password); //如果service校验通过,将用户身份记录到session session.setAttribute("activeUser", activeUser); //重定向到商品查询页面 return "redirect:/first.action"; }
身份认证拦截器
//在执行handler之前来执行的 //用于用户认证校验、用户权限校验 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //得到请求的url String url = request.getRequestURI(); //判断是否是公开 地址 //实际开发中需要公开 地址配置在配置文件中 //从配置中取逆名访问url List<String> open_urls = ResourcesUtil.gekeyList("anonymousURL"); //遍历公开 地址,如果是公开 地址则放行 for(String open_url:open_urls){ if(url.indexOf(open_url)>=0){ //如果是公开 地址则放行 return true; } } //判断用户身份在session中是否存在 HttpSession session = request.getSession(); ActiveUser activeUser = (ActiveUser) session.getAttribute("activeUser"); //如果用户身份在session中存在放行 if(activeUser!=null){ return true; } //执行到这里拦截,跳转到登陆页面,用户进行身份认证 request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response); //如果返回false表示拦截不继续执行handler,如果返回true表示放行 return false; }
授权拦截器
//在执行handler之前来执行的 //用于用户认证校验、用户权限校验 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //得到请求的url String url = request.getRequestURI(); //判断是否是公开 地址 //实际开发中需要公开 地址配置在配置文件中 //从配置中取逆名访问url List<String> open_urls = ResourcesUtil.gekeyList("anonymousURL"); //遍历公开 地址,如果是公开 地址则放行 for(String open_url:open_urls){ if(url.indexOf(open_url)>=0){ //如果是公开 地址则放行 return true; } } //从配置文件中获取公共访问地址 List<String> common_urls = ResourcesUtil.gekeyList("commonURL"); //遍历公用 地址,如果是公用 地址则放行 for(String common_url:common_urls){ if(url.indexOf(common_url)>=0){ //如果是公开 地址则放行 return true; } } //获取session HttpSession session = request.getSession(); ActiveUser activeUser = (ActiveUser) session.getAttribute("activeUser"); //从session中取权限范围的url List<SysPermission> permissions = activeUser.getPermissions(); for(SysPermission sysPermission:permissions){ //权限的url String permission_url = sysPermission.getUrl(); if(url.indexOf(permission_url)>=0){ //如果是权限的url 地址则放行 return true; } } //执行到这里拦截,跳转到无权访问的提示页面 request.getRequestDispatcher("/WEB-INF/jsp/refuse.jsp").forward(request, response); //如果返回false表示拦截不继续执行handler,如果返回true表示放行 return false; }
拦截器配置:
<!--拦截器 --> <mvc:interceptors> <mvc:interceptor> <!-- 用户认证拦截 --> <mvc:mapping path="/**" /> <bean class="cn.itcast.ssm.controller.interceptor.LoginInterceptor"></bean> </mvc:interceptor> <mvc:interceptor> <!-- 授权拦截 --> <mvc:mapping path="/**" /> <bean class="cn.itcast.ssm.controller.interceptor.PermissionInterceptor"></bean> </mvc:interceptor> </mvc:interceptors>
四、什么是Shiro
shiro是apache的一个开源框架,是一个权限管理的框架,实现 用户认证、用户授权。
spring中有spring security (原名Acegi),是一个权限框架,它和spring依赖过于紧密,没有shiro使用简单。
shiro不依赖于spring,shiro不仅可以实现 web应用的权限管理,还可以实现c/s系统,分布式系统权限管理,shiro属于轻量框架,越来越多企业项目开始使用shiro。
Shiro架构:
这里写图片描述
- subject:主体,可以是用户也可以是程序,主体要访问系统,系统需要对主体进行认证、授权。
- securityManager:安全管理器,主体进行认证和授权都 是通过securityManager进行。
- authenticator:认证器,主体进行认证最终通过authenticator进行的。
- authorizer:授权器,主体进行授权最终通过authorizer进行的。
- sessionManager:web应用中一般是用web容器对session进行管理,shiro也提供一套session管理的方式。
- SessionDao: 通过SessionDao管理session数据,针对个性化的session数据存储需要使用sessionDao。
- cache Manager:缓存管理器,主要对session和授权数据进行缓存,比如将授权数据通过cacheManager进行缓存管理,和ehcache整合对缓存数据进行管理。
- realm:域,领域,相当于数据源,通过realm存取认证、授权相关数据。