美文网首页
shiro原理简析+基于springboot基础实践

shiro原理简析+基于springboot基础实践

作者: 灿烂的GL | 来源:发表于2021-04-29 09:16 被阅读0次

    1、shiro原理简析

    架构.png
    原理简析:
    1、subject支持不通调用获取用户信息
    2、SecurityManager安全管理器继承了Authenticator(认证)、Authorizer(授权)、SessionManager、cacheManager(缓存)等,realms域支持不同的数据库做具体授权。
    3、密码生成器通过cryptography

    1、基础方法认证源码分析


    目录结构.png

    主要思路:
    1、从配置文件获取设置的用户密码
    2、校验输入的用户密码
    3、验证结果输出
    shiro的配置文件是ini类型的文件,简单定义几个账号密码,放在resource文件夹下
    格式:# user1 = password, role1, role2, ...

    [users]
    xiaojin=666
    lili=777
    qiqi=888
    

    测试代码

    public class TestAuthenticator {
        public static  void main(String[] arg){
            //1、创建安全管理器对象
            DefaultSecurityManager securityManager = new DefaultSecurityManager();
            //2、给安全管理器设置realm
            securityManager.setRealm(new IniRealm("classpath:shiro.ini"));
    
            //3、工具类设置安全管理器
            SecurityUtils.setSecurityManager(securityManager);
    
            Subject subject = SecurityUtils.getSubject();
            UsernamePasswordToken token = new UsernamePasswordToken("xiaoshi","888");
            try{
                subject.login(token);
                System.out.println("认证成功");
            }catch (UnknownAccountException e){
                e.printStackTrace();
                System.out.println("不知名用户");
            }catch (IncorrectCredentialsException e){
                e.printStackTrace();
                System.out.println("密码错误");
            }
        }
    

    用户认证校验是从login开始的,梳理下用户名认证流程如下:


    认证流程.png

    可以看出想自定义认证的化可以重写最后两个方法,其中SimpleAccountRealm:doGetAuthenticationInfo方法用来校验账号,密码是shiro自动认证的不需要我们修改

    依赖关系.png
    小结:AuthenticatingRealm认证realm 有doGetAuthenticationInfo方法;
    AuthorizingRealm授权relam有doGetAuthorizationInfo方法;SimpleAccountRealm覆盖了这两个方法

    2、spring实现认证
    认证的基本思想:
    1、通过过滤器拦截请求,获取用户信息
    2、匹配数据库中认证/权限信息,可以添加其他功能,比如:密码添加加密认证信息等。
    3、如果内容正确,允许访问,否则重新尝试验证或阻止访问
    下面是重写的配置文件,

    @Configuration
    public class ShiroConfig {
    
        //1、filter
        @Bean
        public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){
            ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
            Map<String,String> map = new HashMap<>();
            //此类请求不拦截
            map.put("/test/login","anon");
             //此类请求需要鉴权
            map.put("/test/logout","authc")
            //通配符可以节省代码量
            map.put("/sysUser/**","authc");
            shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
            shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
            return shiroFilterFactoryBean;
        }
    
        //2、创建安全管理器
        @Bean
        public DefaultWebSecurityManager getDefauleWebSecurity( @Qualifier("realm") Realm realm){
            //上文说的SecurityManager在spring里是DefaultWebSecurityManager 
            DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
            defaultWebSecurityManager.setRealm(realm);
            return defaultWebSecurityManager;
        }
    
        //3、创建自定义realm
        @Bean
        @Qualifier("realm")
        public Realm getRealm(){
            CustomerRealm customerRealm = new CustomerRealm();
    //        //修改凭证校验匹配器
    //        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
    //        hashedCredentialsMatcher.setHashAlgorithmName("MD5");
    //        //添加散列
    //        hashedCredentialsMatcher.setHashIterations(1024);
    //        customerRealm.setCredentialsMatcher(hashedCredentialsMatcher);
            return customerRealm;
        }
    }
    

    对于授权来说用户和角色,角色和授权之间都是多对多的关系,权限下边又会分很多子粒度,重写授权和认证方法如下:

    public class CustomerRealm extends AuthorizingRealm {
        //授权
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
            String primaryPrincipal = (String) principals.getPrimaryPrincipal();
          //根据身份信息获取角色以及权限信息,这里的权限信息实际应该是数据库查询信息
            if("lili".equals(primaryPrincipal)){
                SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
                //这里手动设置的用户具有admin权限,具体权限显示前端可以做角色控制(可以从数据库中查)
                simpleAuthorizationInfo.addRole("user");
                //权限设置:user角色可操作user:*:*粒度权限,需要结合前端标签做权限控制(可以从数据库中查)
                simpleAuthorizationInfo.addStringPermission("user:*:*");
                return simpleAuthorizationInfo;
            }
            return null;
        }
    
        //认证
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
           String principal =  (String) token.getPrincipal();
            //根据身份信息获取密码信息,这里的用户信息实际应该是数据库查询信息
           if("lili".equals(principal)){
               return new SimpleAuthenticationInfo(principal ,"123",this.getName());
           }
            return null;
        }
    }
    

    1、Principals(身份) 是Subject的“标识属性”,可以是任何与Subject相关的标识,比如说名称(给定名称)、名字(姓或者昵称)、用户名、安全号码等等,当然像昵称这样的内容不能很好的对Subject进行独特标识,所以最好的身份信息(Principals)是使用在程序中唯一的标识–典型的使用用户名或邮件地址。
    Primary Principal(最主要的身份)虽然 Shiro 可以使用任何数量的身份,Shiro 还是希望一个程序精确地使用一个主要的身份–一个仅有的唯一标识 Subject 值。在多数程序中经常会是一个用户名、邮件地址或者全局唯一的用户 ID。
    2、Credentials(证明) 通常是只有 Subject 知道的机密内容,用来证明他们真正拥有所需的身份,一些简单的证书例子如密码、指纹、眼底扫描和X.509证书等。

    前端的权限控制,需要把html文件放在static文件夹里(用的是>2.0.3版本的spring,发现不支持jsp了,需要使用html文件)

    <html lang="en" xmlns:th="http://www.thymeleaf.org"
        xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
    <head>
        <meta charset="utf-8" name="viewport"
              content="width=device-width, initial-scale=1.0" http-equiv = "X-UA-Compatible" content ="ie=edge" />
        <title>Docment</title>
    </head>
    <body>
        <h1>系统主页V1.0</h1>
        <!--<a href =${pageContext.request.contextPath}/test/login"> 退出用户</a>-->
        <u1>
            <shiro:hasAnyRoles name="admin,user">
            <li><a href="" >用户管理</a></li>
            <ul>
                <shiro:hasPermission name=" user:add:*">
                    <li><a href="">添加</a> </li>
                </shiro:hasPermission>
                <shiro:hasPermission name=" user:delete:*">
                    <li><a href="">删除</a> </li>
                </shiro:hasPermission>
                <shiro:hasPermission name=" user:update:*">
                    <li><a href="">更新</a> </li>
                </shiro:hasPermission>
            </ul>
            </shiro:hasAnyRoles>
            <shiro:hasRole name="admin">
                <li><a href="" >订单管理</a></li>
                <li><a href="" >商品管理</a></li>
                <li><a href="" >物流管理</a></li>
            </shiro:hasRole>
        </u1>
    </body>
    </html>
    

    登录文件:

    <html lang="en">
    <head>
        <meta charset="utf-8" name="viewport"
              content="width=device-width, initial-scale=1.0" http-equiv = "X-UA-Compatible" content ="ie=edge" />
        <title>Docment</title>
    </head>
    <body>
    <h1>用户登录</h1>
    <form action="./index.html" >
        用户名:<input type="text" name="username"> <br/>
        密码:<input type="text" name ="password"><br/>
        <button type="submit">登录</button><button type="reset">取消</button>
    </form>
    </body>
    </html>
    

    此外还可以通过注解的方式进行角色校验 @RequiresRoles("角色"),如果是多个角色即 @RequiresRoles("角色1","角色2"),需要注意的是这里的意思是拥有角色1或者角色2的权限,CustomerRealm里也需要进行相应配置; 权限校验 @RequiresPermissions("user::")


    3、缓存和过滤器
    缓存支持:
    1、ehcache管理
    2、Redis集中管理

          <dependency>
                <groupId>org.apache.shiro</groupId>
                <artifactId>shiro-ehcache</artifactId>
                <version>1.5.3</version>
            </dependency>
     <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-redis</artifactId>
            </dependency>
    

    设置ehcache缓存

        //3、创建自定义realm
        @Bean
        @Qualifier("realm")
        public Realm getRealm(){
            CustomerRealm customerRealm = new CustomerRealm();
            //修改凭证校验匹配器
    //        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
    //        hashedCredentialsMatcher.setHashAlgorithmName("MD5");
    //        //添加散列
    //        hashedCredentialsMatcher.setHashIterations(1024);
    //        customerRealm.setCredentialsMatcher(hashedCredentialsMatcher);
    
            customerRealm.setCacheManager(new EhCacheManager());
            customerRealm.setCachingEnabled(true);
            customerRealm.setAuthenticationCachingEnabled(true);
            customerRealm.setAuthorizationCachingEnabled(true);
            return customerRealm;
        }
    

    EhCacheManager继承了CacheManager返回的是Cache<K, V> ,如果想用redis缓存也可以继承CacheManager,定义redis的Cache<K, V>
    持续更新中...


    参考链接
    1、官网十分钟入门-详情可以自己点点doc
    2、授权

    相关文章

      网友评论

          本文标题:shiro原理简析+基于springboot基础实践

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