• shiro与springMVC整合


    注:该文基于springMVC已经配置好。

    1. 架构预览

    项目结构
    这里写图片描述

    shiro所需jar包
    这里写图片描述

    2. 整合shiro

    2.1 配置web.xml

    注意,由于shiro的主要作用就是拦截判断,所以我们不再需要springMVC的LoginInterceptorPermissionInterceptor拦截器了。其余的springMVC配置的代码保持不变。
    在web.xml里添加shiroFilter:该过滤器名字将与spring.xml里注入的过滤器名字一致。所以当有请求时进了web.xml里时,请求就会被该过滤器转到spring.xml里的shiro过滤器。

    
    
        shiroFilter
        org.springframework.web.filter.DelegatingFilterProxy
        
        
            targetFilterLifecycle
            true
        
        
        
            targetBeanName
            shiroFilter
        
    
    
        shiroFilter
        /*
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    2.2 配置spring.xml

    (本人将shiro的配置直接配在该文件下的,一般会新建一个shiro自己的配置文件,就像springMVC的springMVC-servlet.xml文件一样)

    
            
            
                
            
            
                 
                    /refuse.jsp = anon
                    /login.do = authc   
                    /logout.do = logout        
                    /** = authc         
                
            
    
        
    
        
          
              
          
    
        
          
              
          
    
        
        
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    securityManager:安全管理器。是必须注入的,所有的过滤都被它管理着。

    loginUrl:没有登录时就会跳转到它指定的地址,如果不指定该属性,则会自动去找项目的根目录下的”/login.jsp”页面。

    unauthorizedUrl:没有权限时默认的跳转路径。

    filterChainDefinitions:过滤链。它可对路径进行过滤。如:
    /refuse.jsp = anon anon过滤器表示认证不通过也可访问,所以这句代码表示refuse.jsp路径在没有登录时也可访问
    /login.do = authc authc过滤器表示需要认证通过才可访问,也就是说login.do在没有登录时,是不能访问的,除非设为了loginUrl的值。

    2.3 默认拦截器

    过滤器简称

    类名

    解释

    示例

    1.认证过滤器

    anon

    org.apache.shiro.web.filter.authc.AnonymousFilter

    可匿名访问。无参,一般用于过滤静态资源

    /admins/**=anon 表示admins下的所有路径皆可匿名访问`

    authc

    org.apache.shiro.web.filter.authc.FormAuthenticationFilter

    认证登录后才可访问。

    /admins/user/**=authc

    authc属性

    usernameParam:表单提交的用户名参数名( username); passwordParam:表单提交的密码参数名(password); rememberMeParam:表单提交的密码参数名(rememberMe);

    loginUrl:登录页面地址(/login.jsp);successUrl:登录成功后的默认重定向地址;

    failureKeyAttribute:登录失败后错误信息存储key(shiroLoginFailure);

    authcBasic

    org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter

    http身分认证器。无参

    /admins/user/**=authcBasic

    authcBasic属性

    applicationName:弹出登录框显示的信息(application);

    user

    org.apache.shiro.web.filter.authc.UserFilter

    表示必须存在用户

    /admins/user/**=user 表示身份认证通过或通过记住我认证通过的可以访问,此时进行登录操作不会做检查

    logout

    org.apache.shiro.web.filter.authc.LogoutFilter

    退出拦截器

    /logout.do=logout

    主要属性

    redirectUrl:退出成功后重定向的地址(/)

    2.授权过滤器

    perms

    org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter

    权限授权过滤器。有参,多参时写成拼接字符串,各参之间以逗号分隔。多参时需每个权限都通过时才算通过,相当于hasAllRoles()

    单参:/admins/user/**=perms[add] 表示该路径只有add权限时才可访问。多参:/admins/user/**=perms["add,delete"]

    port

    org.apache.shiro.web.filter.authz.PortFilter

    端口过滤器

    /admins/user/**=port[8080] 当端口号不是8080时会将访问url的端口改为8080后再跳转。

    主要属性

    port(80):指定可以通过的端口

    roles

    org.apache.shiro.web.filter.authz.RolesAuthorizationFilter

    角色授权过滤器,可多参

    属性

    loginUrl:登录页面地址;unauthorizedUrl:未授权后重定向的地址;

    admins/user/**=roles[“admin,guest”] 多参时,都通过才算通过

    rest

    org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter

    请求方法拦截器(GET=read,POST=create,PUT=update,DELETE=delete,HEAD=read,TRACE=read,OPTIONS=read, MKCOL=create),它自动根据请求方法构建权限字符串。/admins/user/**=perms[user:post]会拼接“user:create”权限字符串

    /users=rest[user],会自动拼出“user:read,user:create,user:update,user:delete”权限字符串进行权限匹配(所有都得匹配,isPermittedAll);

    ssl

    org.apache.shiro.web.filter.authz.SslFilter

    安全协议拦截器,只有请求协议是https才能通过;否则自动跳转会https端口(443);其他和port拦截器一样;

    /admins/user/**=ssl

    2.4 自定义realm

    此realm先不从数据库查询权限数据

    /**** 
     * 自定义Realm 
     *  
     * @author Peter
     *  
     */  
    public class MyShiroRealm extends AuthorizingRealm {  
    
        @Override
        public String getName() {
            return"customRealm";
        }
    
    
        // 支持什么类型的token
        @Override
        public boolean supports(AuthenticationToken token) {
            return token instanceof UsernamePasswordToken;
        }
    
        /*** 
         * 获取授权信息 
         */  
        @Override  
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pc) {  
    
            //先自定义一个query权限,就不从数据库查询了 
            String username = (String) pc.fromRealm(getName()).iterator().next();  
            if (username != null) {  
                SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
                info.addStringPermission("query");//权限
                return info;  
            }          
            return null;  
        }  
        /*** 
         * 获取认证信息 
         * 
         * 问题:如何在登录后不再进登录页面了呢???????????????????????????
         */  
        @Override  
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken at) {  
            UsernamePasswordToken token = (UsernamePasswordToken) at;  
            // 通过表单接收的用户名  
            // String username = token.getUsername();  
            String username = (String) at.getPrincipal();
    
            if (username != null && !"".equals(username)) {  
                User user = accountService.getUserByUserName(username); 
                if (user != null && user.getPassword().equals(new String(token.getPassword())) && user.getUsername().equals(token.getUsername())) {  
                    return new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), getName());  
                }else{
                     //throw new UnknownAccountException(); //如果用户名错误 
                    throw new IncorrectCredentialsException(); //如果密码错误 
                }
            }  
    
            return null;  
        }  
    
        /**用户的业务类**/  
        private IAccountService accountService;  
    
        public IAccountService getAccountService() {  
            return accountService;  
        }  
    
        public void setAccountService(IAccountService accountService) {  
            this.accountService = accountService;  
        }  
    
    }  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72

    2.5 登录

     /*** 
      * 提交数据的登录
      */  
     @RequestMapping(value = "login.do")  
     public String login(String username, String password,ModelMap model) {  
        Subject subject = SecurityUtils.getSubject(); 
        if(subject.isAuthenticated()){
            return "home.jsp";
        }else{
            UsernamePasswordToken token = new UsernamePasswordToken(username, password);  
          String error = null;
          try {  
              subject.login(token);  
             // subject.logout();
          } catch (UnknownAccountException e) {  
              error = "用户名/密 错误";  
          } catch (IncorrectCredentialsException e) {  
              error = "用/密码 错误";  
          } catch (AuthenticationException e) {  
              //其他错误,比如锁定,如果想单独处理请单独catch处理  
              error = "其他错误:" + e.getMessage();  
          } 
    
          model.addAttribute("msg", error);
          System.out.println("用户认证状态:"+subject.isAuthenticated());
    
          if(subject.isAuthenticated()){
            return "redirect:home"; 
          }else{
            return "/login.jsp"; 
          }      
    
        }
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    2.6 退出

    由于shiro的sessionManager管理session,所以不用开发退出功能,直接使用shiro的logout拦截器即可退出。
    
    
    
    /logout.do= logout
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2.7 无权限访问跳转到refuse.jsp

    当用户无操作权限,shiro将跳转到refuse.jsp页面。
    使用注解的方式赋的权限,首先看看controller里通过注解限定的权限:

     /**
         * 查询:注解query权限:只有当realm里查回的权限里有query时才可访问该方法
         * 
         * 即访问该方法时,会先拿query权限去realm里查看授权时查回的权限里是否有query权限
         * 有的话则允许访问,否则不允许
         * @return
         * @author Peter
         */
        @RequestMapping(value = "query")
        @RequiresPermissions("query")//指定访问的权限
        public String query(){
            System.out.println("查询内容");
            return "/home.jsp";
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    当没有权限访问时,就会跳转到refuse.jsp页面,但是注解方式配置无权限跳转需要在springMVC的配置文件(springMVC-servlet.xml)里配,可能是因为shiro注解赋权限的配置在这里面吧。代码如下:

    
      
          
     
    
    
    
        
            
                
                /refuse
            
        
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
  • 相关阅读:
    追梦之旅:中国人民大学加拿大女王大学金融硕士项目,成就你的金融梦想
    Vue3 常用组件
    基础数据结构之——【顺序表】(上)
    现代控制理论课程实验三:一阶倒立摆的LQR控制器设计
    【开发教程4】开源蓝牙心率防水运动手环-外部 Flash 读写
    【数据结构】选择题快速求解AOE网的关键路径
    Appium自动化测试<三>
    远程控制桌面软件是否支持远程防护墙配置
    Golang标准库
    Linux学习之进程通讯(IPC)—进程之间的通信
  • 原文地址:https://blog.csdn.net/web13985085406/article/details/126496221