• shiro整合springboot


    shiro
    • Subject : 主体,一般指用户
    • SecurityManager:安全管理器,,管理所有的Subject
    • Realms : 用于进行权限信息的验证,一般需要自己实现

    Subject方法:
    getSession()
    isAuthenticated() 是否已经登录
    login()
    logout()
    getPrincipal() 获取标识信息:用户名,邮箱,
    hasRole() 是否具有某个角色
    hasPermisson() 是否具有某个权限

    获取Subject:
    SecurityUtils.getSubject()

    SecurityManager属性
    Authenticator 认证器
    Authorizer 授权器

    在这里插入图片描述

    在这里插入图片描述

    认证策略:
    ModularRealmAuthenticatorsetAuthenticationStrategy() 方法中配置认证策略
    shiro有三种认证策略:

    1. AllSuccessfulStrategy
    2. AtLeastOneSuccessfulStrategy
    3. FirstSuccessfulStrategy
    代码:

    实体类:

    @Data
    @AllArgsConstructor
    public class User {
    
        private String id;
        private String username;
        private String password;
        
        private HashSet<Role> roles;
    }
    
    @Data
    @AllArgsConstructor
    public class Role {
        private String id;
        private String roleName;
    
        private Set<Permission> permissions;
    }
    
    @Data
    @AllArgsConstructor
    public class Permission {
        private String id;
        private String permissionName;
    }
    
    
    • 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

    LoginService模仿从数据库中获取的数据:

    @Service
    public class LoginServiceImpl implements LoginService{
    
    
        @Override
        public User getUserByName(String username) {
            return getMapByName(username);
        }
    
    
        public User getMapByName(String username){
            Permission permission1 = new Permission("1", "query");
            Permission permission2 = new Permission("2", "add");
    
            HashSet<Permission> permissionSet = new HashSet<>();
            permissionSet.add(permission1);
            permissionSet.add(permission2);
    
            Role role = new Role("!", "admin", permissionSet);
            HashSet<Role> roleSet = new HashSet<>();
            roleSet.add(role);
    
            User user = new User("1", "cc", "123", roleSet);
    
            HashMap<String, User> map = new HashMap<>();
            map.put(user.getUsername(),user);
    
    //        权限2
            HashSet<Permission> permissionSet2 = new HashSet<>();
            // query
            permissionSet2.add(permission1);
    //        角色2
            Role role2 = new Role("2", "user", permissionSet2);
            HashSet<Role> roleSet2 = new HashSet<>();
            roleSet2.add(role2);
    
            // 只读 user
            User user1 = new User("2", "zs", "123", roleSet2);
    
            map.put(user1.getUsername(),user1);
    
            return map.get(username);
        }
    }
    
    
    • 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

    realms:

    @Component
    public class CustomRealm extends AuthorizingRealm {
        @Autowired
        LoginService loginService;
    
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
            // 获取登录用户名
            String name = principals.getPrimaryPrincipal().toString();
    
            User user = loginService.getUserByName(name);
    
            if(user == null){
                return null;
            }
    
            SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
    
            for (Role role : user.getRoles()) {
                simpleAuthorizationInfo.addRole(role.getRoleName());
    
                for (Permission permission : role.getPermissions()) {
                    simpleAuthorizationInfo.addStringPermission(permission.getPermissionName());
                }
            }
            // 返回这个角色 具有的权限信息
            return simpleAuthorizationInfo;
        }
    
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
            if(StringUtils.isEmpty(token.getPrincipal())){
                return null;
            }
            // 获取用户信息
            String name = token.getPrincipal().toString();
            User user = loginService.getUserByName(name);
            if(user == null){
                // 这里返回后会报出对应的异常
                return null;
            }else{
                // 返回数据库 查出来的信息
                SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(name, user.getPassword(), this.getName());
                //  返回这个角色 具有的认证信息
                return  simpleAuthenticationInfo;
            }
        }
    }
    
    • 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
    @Component
    public class Realm01 extends AuthorizingRealm {
    
        /**
         * 这个Realm 不做认证工作,,单纯只是为了测试  认证策略
         * @param token
         * @return
         * @throws AuthenticationException
         */
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
           // 输入什么 返回什么,怎么都成功
            return new SimpleAuthenticationInfo(token.getPrincipal(),token.getCredentials(),getName());
        }
    
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
            return null;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    shiro配置文件: securityManager配置多realm下的认证策略,,,ShiroFilterFactoryBean工厂配置过滤条件:

    @Configuration
    public class ShiroConfig {
    
    
    
        @Autowired
        CustomRealm customRealm;
    
        @Autowired
        Realm01 realm01;
    
        @Bean
        public DefaultWebSecurityManager defaultWebSecurityManager(){
            DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
    //        securityManager.setRealm(customRealm);
    
            // 同时返回所有 登录成功realm信息
            AtLeastOneSuccessfulStrategy atLeastOneSuccessfulStrategy = new AtLeastOneSuccessfulStrategy();
    
            // 只返回第一个 认证成功的realm信息,,即使已经有 realm 认证成功了,还是会去继续调用后面剩下的Realm 进行认证操作
            FirstSuccessfulStrategy firstSuccessfulStrategy = new FirstSuccessfulStrategy();
    
    
    
            // 所有成功
            AllSuccessfulStrategy allSuccessfulStrategy = new AllSuccessfulStrategy();
            ModularRealmAuthenticator authenticator = new ModularRealmAuthenticator();
            securityManager.setAuthenticator(authenticator);
            authenticator.setAuthenticationStrategy(atLeastOneSuccessfulStrategy);
            ArrayList<Realm> realms = new ArrayList<>();
            realms.add(realm01);
            realms.add(customRealm);
            securityManager.setRealms(realms);
            return securityManager;
        }
    
        // filter工厂,,设置对应的过滤条件和跳转条件
        @Bean
        public ShiroFilterFactoryBean shiroFilterFactoryBean(){
            ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
            // 设置安全管理器
            bean.setSecurityManager(defaultWebSecurityManager());
    
    
            /**
             * 添加shiro  内置过滤器
             * anon  匿名
             * authc  认证了
             * users  必须拥有记住我 功能 才能访问
             * perms:  拥有对某个资源的权限才能访问
             * role: 拥有某个角色权限
             */
            HashMap<String, String> filterMap = new HashMap<>();
            // 登出
            filterMap.put("logout","logout");
            filterMap.put("/**","authc");
            // 访问不了的时候,跳转到登录页面
            bean.setLoginUrl("/doLogin");
            // 登录成功
            bean.setSuccessUrl("/index");
            bean.setFilterChainDefinitionMap(filterMap);
    
            return bean;
        }
    
    
        /**
         * 开启 shiro aop 注解支持,否则 @RequiresRoles 等注解无法生效
         * @return
         */
        @Bean
        public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(){
            AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
            authorizationAttributeSourceAdvisor.setSecurityManager(defaultWebSecurityManager());
            return authorizationAttributeSourceAdvisor;
        }
    
    
        /**
         * 开启 shiro aop 注解支持,否则 @RequiresRoles 等注解无法生效,,,这个不写@RequirePermission生效,@RequiresRoles不生效
         * @return
         */
        @Bean
        public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
            DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
            advisorAutoProxyCreator.setProxyTargetClass(true);
            return advisorAutoProxyCreator;
        }
    }
    
    
    • 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
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90

    全局异常处理

    @ControllerAdvice
    public class GlobalExceptionHandler {
    
        @ExceptionHandler
        @ResponseBody
        public String ErrorHandler(AuthorizationException e){
            System.out.println("没有权限"+e.getMessage());
            return "no permission";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    controller:

    @RestController
    public class LoginController {
    
    
        @PostMapping("/doLogin")
        public String login(String username, String password, Model model){
            Subject subject = SecurityUtils.getSubject();
    
            UsernamePasswordToken token = new UsernamePasswordToken(username, password);
            try {
                subject.login(token);
    //            subject.checkRole("admin");
    //            subject.checkPermissions("query","add");
                // 获取登录成功的用户信息
                // 如果是多个
                PrincipalCollection principals = subject.getPrincipals();
                List list = principals.asList();
                System.out.println(list);
                for (Object o : list) {
                    System.out.println(o.getClass()+"=======>"+o);
                }
    
                return "login success";
            } catch (UnknownAccountException e) {
               return "unknown account";
            }catch (IncorrectCredentialsException e){
                return "incorrect credentials";
            }catch (AuthorizationException e){
                return "no authorization";
            }
    
        }
    
        @GetMapping("/logout")
        public String logout(){
            Subject subject = SecurityUtils.getSubject();
            subject.logout();
            return "logout";
        }
    
        @RequiresRoles("admin")
        @GetMapping("/hello")
        public String hello(){
            return "hello";
        }
    
        @RequiresPermissions("query")
        @GetMapping("/index")
        public String index(){
            return "index";
        }
    
        @RequiresPermissions("add")
        @GetMapping("/add")
        public String add(){
            Subject subject = SecurityUtils.getSubject();
            subject.checkPermission("add");
            return "add success";
        }
    }
    
    
    • 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
    shiro常见异常

    认证异常

    1. AuthenticationException 认证异常
    2. CredentialsException 凭证异常
      • IncorrectCredentialsException 不正确的凭证
      • ExpiredCredentialsException 过期的凭证
    3. AccountException 账号异常
      • ConcurrentAccessException 并发访问异常,(多个用户同时登录时抛出)
      • UnknowAccountException 未知的账号
      • ExcessiveAttemptsException 认证次数超过限制
      • DisabledAccountException 禁用的账号
      • LockedAccountException 账号被锁定
      • UnsupportedTokenException 使用了不支持的 token

    授权异常
    4. AuthorizationException

    • UnauthorizedException : 抛出以指示请求的操作或对请求的资源的访问是不允许的
    • UnanthenticatedException : 当尚未完成成功认证时,尝试执行授权操作时,发生的异常
    遇到的问题

    No realms have been configured! One or more realms must be present to execute an authorization operation.
    解决: shiro必须先设置 认证器,再进行 realm 设置
    在这里插入图片描述
    引用: https://blog.csdn.net/sword_anyone/article/details/117852515

    @RequiresRoles不起作用
    在springboot中配置shiro,,结果@RequiresRoles ,,@RequiresPermission 等注解都无效
    解决:
    在shiro的配置文件中,注入 开启 支持aop,代理的bean:

    @Configuration
    public class ShiroConfiguration {
         /**
         *  开启shiro aop注解支持.否则@RequiresRoles等注解无法生效
         *  使用代理方式;
         * @param securityManager
         * @return
         */
        @Bean
        public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
            AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
            authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
            return authorizationAttributeSourceAdvisor;
        }
    
        /**
         * 自动创建代理
         * @return
         */
        @Bean
        @DependsOn({"lifecycleBeanPostProcessor"})
        public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
            DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
            advisorAutoProxyCreator.setProxyTargetClass(true);
            return advisorAutoProxyCreator;
        }
    
    
    }
    
    • 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

    引用: http://www.wjhsh.net/expiator-p-8621847.html

    git:https://github.com/water-kid/code/tree/master/shiro_springboot

    引用:
    https://blog.csdn.net/w399038956/article/details/120434244
    http://t.zoukankan.com/learnhow-p-10090718.html

  • 相关阅读:
    AVR128单片机 自动售水机
    SDK 控件
    H5手机端前端开发调试工具 控制台
    长短时记忆网络(Long Short Term Memory,LSTM)详解
    cmake 中经常出现的 关键词 scope 中的 三种:PUBLIC PRIVATE INTERFACE
    Linux 线程与线程同步
    基于 FPGA 实现 IIC(I2C) 协议控制 EEPROM 读写操作
    App上架Apple App Store和Google Play流程
    Android---打开相册选择图片
    Flutter GPU 是什么?为什么它对 Flutter 有跨时代的意义?
  • 原文地址:https://blog.csdn.net/qq_36022463/article/details/126561342