美文网首页
Shiro框架入门(代码实现)

Shiro框架入门(代码实现)

作者: 摸鱼中的Hy | 来源:发表于2020-05-07 22:15 被阅读0次

    0. 旨要

    用于学习和记录,以方便后期开发和查找。第一次写文章,如有问题,感谢指出!!!

    1. Shiro 简单介绍

    Shiro是一个功能强大且易于使用的Java安全框架,它执行身份验证,授权,加密和会话管理。
    三个核心组件:

    1. Subject :用户主体(把操作交给SecurityManager)
    2. SecurityManager :安全管理器(关联Realm)
    3. Realm :shiro连接数据的桥梁

    2. 项目实战

    环境:springboot + maven + mybatis
    工具:IDEA
    注:springboot 项目搭建就不多说。

    2.1 依赖包

    maven配置

    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.1.1</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <!--    shiro 权限控制-->
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-spring</artifactId>
        <version>1.4.0</version>
    </dependency>
    

    2.2 验证授权配置

    @Slf4j
    public class UserRealm extends AuthorizingRealm {
    
        @Autowired
        private SysUserMapper sysUserMapper;
    
        @Autowired
        private SysMenuMapper sysMenuMapper;
    
        /**
         * 执行授权逻辑
         * @param principalCollection
         * @return
         */
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    
            SysUserEntity principal = (SysUserEntity) principalCollection.getPrimaryPrincipal();
            Set<String> roleCodeSet = new HashSet<>();//用户角色列表
            Set<String> permsSet = new HashSet<>();//用户权限列表
            SysUserRoleEntity sysUserRolesEntity = sysUserMapper.selectAllRoleMenusByUserId(principal.getId());
            List<SysRoleEntity> roles = sysUserRolesEntity.getSysRoleList();
            for (SysRoleEntity role : roles) {
                roleCodeSet.add(role.getCode());
                if (CollectionUtils.isNotEmpty(role.getSysMenuList())) {
                     role.getSysMenuList().stream().forEach(sysMenu -> permsList.add(sysMenu.getPerms()));
                }
            }
            for (String perm : permsList) {
                if (StringUtils.isNotBlank(perm)) {
                    permsSet.addAll(Arrays.asList(perm.trim().split(",")));
                }
            }
    
            SimpleAuthorizationInfo authorInfo = new SimpleAuthorizationInfo();
            authorInfo.setRoles(roleCodeSet);
            authorInfo.setStringPermissions(permsSet);
            return authorInfo;
        }
    
        /**
         * 执行认证逻辑,登录时调用
         * @param authenticationToken
         * @return
         * @throws AuthenticationException
         */
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
            UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
    
            SysUserEntity user = sysUserMapper.selectByUsername(token.getUsername());
            if (user == null) {
                throw  new UnknownAccountException("账号不存在");
            }
            SimpleAuthenticationInfo authInfo = new SimpleAuthenticationInfo(user, user.getPassword(), ByteSource.Util.bytes(user.getSalt()), getName());
            return authInfo;
        }
    }
    

    这里主要要说明下认证时的SimpleAuthenticationInfo对象,一共4个参数,按顺序说明:

    1. 第一个参数为当前用户信息,可以是用户的实体类,也可以是单单的一个用户账号,看个人需求,不过一般都是使用实体类;
    2. 第二个参数为数据库所存储的用户密码,subject.login时用于与token中的密码进行匹配,匹配不上会自动报异常(IncorrectCredentialsException);
    3. 第三个参数为盐,用于加密密码对比。常用的MD5、SHA256等等。注意,使用盐时数据库存储的密码也应是加密后的字符串(可以不设置);
    4. 第四个参数,当前 Realm 名称

    2.3 配置

    @Configuration
    public class ShiroConfig {
    
        /**
         * 创建 Realm
         */
        @Bean
        public UserRealm myShiroRealm(CredentialsMatcher matcher) {
            UserRealm realm = new UserRealm();
            realm.setCredentialsMatcher(matcher);
            return realm;
        }
    
        /**
         * 创建安全管理器
         */
        @Bean
        public SecurityManager securityManager(UserRealm realm) {
            DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
            securityManager.setRealm(realm);
            return securityManager;
        }
    
        /**
         * 配置过滤器
         */
        @Bean
        public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
            ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
            shiroFilterFactoryBean.setSecurityManager(securityManager);
            shiroFilterFactoryBean.setLoginUrl("/login");
            shiroFilterFactoryBean.setSuccessUrl("/index");
            shiroFilterFactoryBean.setUnauthorizedUrl("/403");
    
            Map<String, String> filterChainMap = new LinkedHashMap<>();
            filterChainMap.put("/webjars/**", "anon");
            filterChainMap.put("/logout", "logout");
            filterChainMap.put("/login", "anon");
            filterChainMap.put("/**", "authc");
            shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainMap);
            return shiroFilterFactoryBean;
        }
        /**
         * 密码加密验证
         * @return
         */
        @Bean
        public HashedCredentialsMatcher hashedCredentialsMatcher() {
            HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
            matcher.setHashAlgorithmName("SHA-256");
            matcher.setHashIterations(16);
            return matcher;
        }
    
        /**
         * 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证
         * @return
         */
        @Bean
        public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
            DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
            advisorAutoProxyCreator.setProxyTargetClass(true);
            return advisorAutoProxyCreator;
        }
    
        /**
         * 开启aop注解支持
         * @param securityManager
         * @return
         */
        @Bean
        public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
            AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
            advisor.setSecurityManager(securityManager);
            return advisor;
        }
    }
    

    2.3.1 ShiroFilterFactoryBean 说明

    主要说明下loginUrlfilterChainMap

    1) loginUrl

    没有登录的用户请求需要登录的页面时自动跳转到登录页面,可配置也可不配置,但是不配置的话,会默认查找web下的login.jsp;

    2) filterChainMap

    Shiro内置过滤器,可以实现权限相关的拦截(url),依照顺序优先匹配,可以使用自定义的filter去覆盖。这里说的只是默认的拦截,没涉及到自定义filter。以下是一些常用的拦截配置说明:

    1. anon: 无需认证
    2. authc: 需要认证才可以访问
    3. user: 如果使用了rememberMe的功能可以直接访问
    4. perms: 该资源必须得到资源权限才可以访问
    5. roles: 该资源必须得到角色权限才可以访问

    <font color=red>注:配置时注意别拦截自己的静态资源</font>

    2.4 使用

    以上1、2、3 步骤已经完成了Shiro的简单配置,也可以使用了

    2.4.1 登录

       @PostMapping("/login")
       public String doLogin(String username, String password, Model model) {
           //1. 封装用户数据
           UsernamePasswordToken token = new UsernamePasswordToken(username, password);
           //2. 获取Subject
           Subject subject = SecurityUtils.getSubject();
           //3. 执行登录操作
           try {
               subject.login(token);
           } catch (IncorrectCredentialsException ice) {
               model.addAttribute("msg", "密码不正确");
               return "login";
           } catch (UnknownAccountException uae) {
               model.addAttribute("msg", "账号不存在");
               return "login";
           } catch (AuthenticationException ae) {
               model.addAttribute("msg", "状态不正常");
               return "login";
           }
           model.addAttribute("username", username);
           return "index";
       }
    

    2.4.2 控制器访问权限控制

        @RequestMapping("/info")
        @RequiresPermissions("sys:user:info")//需要在Shiro配置文件里配置AOP才能生效
        public R getUserInfo(Long userId){
            ...
            return R;
        }
    

    2.4.3 Shiro获取用户主体

    SecurityUtils.getSubject().getPrincipal();
    

    相关文章

      网友评论

          本文标题:Shiro框架入门(代码实现)

          本文链接:https://www.haomeiwen.com/subject/jumzghtx.html