zoukankan      html  css  js  c++  java
  • (十二)springboot中shiro的使用

    一、引入maven配置

    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-spring</artifactId>
        <version>1.4.0</version>
    </dependency>

    二、建表

    用户表、角色表、权限表、用户角色表、角色权限表。

    用户表:

    image.png

    角色表:

    image.png

    权限表:news:* 表示有新闻的所有权限(包括增删改查),而news:add,只有新闻的新增权限。

    image.png

    用户角色表:用户拥有哪些角色。

    image.png

    角色权限表:角色拥有哪些权限。

    image.png

    三、自定义Realm

    自定义realm主要用于用户的权限验证以及登录验证。

    自定义realm继承AuthorizingRealm类,并重写doGetAuthorizationInfo和doGetAuthenticationInfo方法,doGetAuthorizationInfo方法主要校验用户的权限,即该用户拥有什么角色以及权限。doGetAuthenticationInfo用于校验登录验证,即用户的用户名或者密码是否正确。

    /**
     * 类名 : shiro的Realm
     * 用法 :
     * 创建人 : shyroke
     * 时间:2018/12/12 17:29
     */
    public class MyRealm extends AuthorizingRealm {
    
        @Autowired
        private UserMapper userMapper;
    
        @Autowired
        private PermissionMapper permissionMapper;
    
    
        /**
         * 授权,即该用户拥有什么角色以及权限
         * 步骤:根据用户名获取角色以及权限,然后设置到验证信息类并返回。
         * @param principalCollection
         * @return
         */
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    
            String userName = principalCollection.getPrimaryPrincipal().toString();
    
    //        获取该用户的角色
            List<Role> roles = userMapper.getRolesByUserName(userName);
            Set<String> roleSets = new HashSet<>();
    
    //        获取该用户的权限集
            List<Permission> permissions = new ArrayList<>();
            Set<String> permissoinSet = new HashSet<>();
    
            //将List转为Set
            if(roles !=null && roles.size()>0){
                for(Role role:roles){
                    roleSets.add(role.getName());
                    permissions.addAll(permissionMapper.getPermissionByRoleId(role.getId()));
                }
            }
    
            //将List转为Set
            if(permissions!=null & permissoinSet.size()>0){
                for(Permission p :permissions){
                    permissoinSet.add(p.getName());
                }
            }
    
    
            info.addRoles(roleSets);
            info.addStringPermissions(permissoinSet);
    
            return info;
        }
    
    
        /**
         * 认证,即用户账号密码是否正确
         * @param token
         * @return
         * @throws AuthenticationException
         */
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    //        获取用户名和密码
            String userName = (String)token.getPrincipal();
            String passWord = new String((char[]) token.getCredentials());
    
    //        根据用户名查找该用户
            User user =  userMapper.getUserByName(userName);
    
    
            if(user == null){
                throw new UnknownAccountException("用户名不存在");
            }
    
            if(!user.getPassword().equals(passWord)){
                throw new IncorrectCredentialsException("密码错误");
            }
    
            SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user.getName(),user.getPassword(),getName());
    
            return info;
        }
    }

    四、shiro配置类

    /**
     * 类名 :shiro的核心配置类
     * 用法 :
     * 创建人 : shyroke
     * 时间:2018/12/14 15:20
     */
    @Configuration
    public class ShiroConfigration {
    
    //    设置自定义Realm
        @Bean
        public MyRealm myRealm(){
            return new MyRealm();
        }
    
    //    权限管理,配置主要是Realm的管理认证
        @Bean
        public SecurityManager securityManager(){
            DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
            manager.setRealm(myRealm());
            return manager;
        }
    
    
        /**
         * 设置过滤条件和跳转条件
         * anon 不生效的原因:1、map的类型必须是LinkedHashMap 2、anon必须定义在authc之前
         *
         * @param securityManager
         * @return
         */
        @Bean
            public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager){
                ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
                factoryBean.setSecurityManager(securityManager);
    
    //            设置登录跳转
                factoryBean.setLoginUrl("/admin");
                factoryBean.setSuccessUrl("/admin/index");
    
                //必须为LinkedHashMap 否则anon不生效
                Map<String,String> map = new LinkedHashMap<>();
    
                //退出
                map.put("/admin/logout","logout");
    
                //登录页面和登录验证不要拦截
                map.put("/admin/login.html","anon");
                map.put("/admin/tologin","anon");
    
                //设置需要过滤的链接
                map.put("/admin/**","authc");
    
    
    
                factoryBean.setFilterChainDefinitionMap(map);
    
                return factoryBean;
            }
    
    
        /**
         *  开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证
         * 配置以下两个bean(DefaultAdvisorAutoProxyCreator和AuthorizationAttributeSourceAdvisor)即可实现此功能
         * @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 authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
            authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
            return authorizationAttributeSourceAdvisor;
        }
    
    }

    五、调用

    代码如下,当调用Subject.login方法后,会调用自定义Realm的doGetAuthenticationInfo方法校验用户名密码是否正确,如果不正确则抛出对应异常,controller层捕获并处理异常。

    AuthenticationToken usernamePasswordToken = new UsernamePasswordToken(user.getName(),user.getPassword());
    
    Subject subject = SecurityUtils.getSubject();
    
    
    try {
        subject.login(usernamePasswordToken);
    }catch (UnknownAccountException ex) {
        logger.info("用户名错误!");
        return R.error("用户名错误!");
    } catch (IncorrectCredentialsException ex) {
        logger.info("密码错误!");
        return R.error("密码错误!");
    } catch (AuthenticationException ex) {
        logger.info(ex.getMessage());
        return R.error("系统错误,请查看日志");
    } catch (Exception ex) {
        logger.info(ex.getMessage());
        return R.error("系统错误,请查看日志");
    }
  • 相关阅读:
    Educational Codeforces Round 6
    Educational Codeforces Round 5
    [Educational Round 5][Codeforces 616F. Expensive Strings]
    [Codeforces Round #508 (Div. 2)][Codeforces 1038E. Maximum Matching]
    Codeforces Round #509 (Div. 2)
    从零开始编写一个vue插件
    Web前端错题模糊题记录
    vue中响应式props办法
    vue中router-link的click事件失效的解决办法
    ubuntu修改顶栏颜色
  • 原文地址:https://www.cnblogs.com/shyroke/p/10138697.html
Copyright © 2011-2022 走看看