• shiro源码分析


    个人学习路线

    Apache Shiro是一个功能强大且灵活的开源安全框架,可以清晰地处理身份验证,授权,企业会话管理和加密。

    这是它的官网:

    官网
    在官网上面有个快速开始,将源码下载下来,
    看看shiro的大体架构:http://shiro.apache.org/architecture.html
    我就贴一张最重要的图好了,官网介绍的更加清楚.
    在这里插入图片描述

    跑一遍快速开始:
    在这里插入图片描述
    这时候对shiro有个简单的了解了…

    简单介绍

    ini配置文件:

    # 用户名,密码,角色
    [users]
    root = secret, admin
    guest = guest, guest
    
    presidentskroob = 12345, president
    darkhelmet = ludicrousspeed, darklord, schwartz
    lonestarr = vespa, goodguy, schwartz
    
    $ 角色 ,对应的权限
    [roles]
    admin = *
    schwartz = lightsaber:*,aa:*
    goodguy = winnebago:drive:eagle5,aa:*
    

    简单看看事例代码:

    public class Quickstart {
        private static final transient Logger log = LoggerFactory.getLogger(Quickstart.class);
        public static void main(String[] args) {
            //创建安全中心
            Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
            SecurityManager securityManager = factory.getInstance();
            //通过提供的类去简化操作
            SecurityUtils.setSecurityManager(securityManager);
    
            //获取个用户,抽象的用户.
            Subject currentUser = SecurityUtils.getSubject();
    
            //获取session
            Session session = currentUser.getSession();
            session.setAttribute("someKey", "aValue");
            String value = (String) session.getAttribute("someKey");
            if (value.equals("aValue")) {
                log.info("Retrieved the correct value! [" + value + "]");
            }
    
            //判断是登录
            if (!currentUser.isAuthenticated()) {
                //用户名密码
                UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");
                token.setRememberMe(true);
                try {
                    //登录,没有抛出异常就是认证成功,抛出了就是登录失败了.
                    currentUser.login(token);
                    //各种异常,顾名思义.账户不存在啊,密码错误啊,用户锁住了等等..
                } catch (UnknownAccountException uae) {
                    log.info("There is no user with username of " + token.getPrincipal());
                } catch (IncorrectCredentialsException ice) {
                    log.info("Password for account " + token.getPrincipal() + " was incorrect!");
                } catch (LockedAccountException lae) {
                    log.info("The account for username " + token.getPrincipal() + " is locked.  " +
                            "Please contact your administrator to unlock it.");
                }
                catch (AuthenticationException ae) {
                    //unexpected condition?  error?
                }
            }
    
            //登录成功,获取用户
            log.info("User [" + currentUser.getPrincipal() + "] logged in successfully.");
    
            //是否有指定的角色
            if (currentUser.hasRole("schwartz")) {
                log.info("May the Schwartz be with you!");
            } else {
                log.info("Hello, mere mortal.");
            }
    
            //是否有指定的权限
            if (currentUser.isPermitted("lightsaber:weild")) {
                log.info("You may use a lightsaber ring.  Use it wisely.");
            } else {
                log.info("Sorry, lightsaber rings are for schwartz masters only.");
            }
    
          
            //退出
            currentUser.logout();
    
            System.exit(0);
        }
    }
    

    怎么进行认证(登录)的

    代码是通过subject调用login方法登录,点到具体实现.
    DelegatingSubject这个类实现了Subject,实现了login方法:

        Subject currentUser = SecurityUtils.getSubject();
       currentUser.login(token);
    

    SecurityManager详解

    我们看默认的实现DefaultSecurityManager类的uml图,
    在这里插入图片描述
    DefaultSecurityManager继承了SessionsSecurityManager(可以进行session管理)->AuthorizingSecurityManager(可以进行鉴权)->AuthenticatingSecurityManager(可以进行认证)->RealmSecurityManager(可以进行real管理)->CachingSecurityManager(缓存管理了);这不是很明显的装饰者吗?

    CachingSecurityManager

    这是CachingSecurityManager有CacheManager接口,我们可以实现自己的缓存管理,可以放在redis里,或者mysql,或者整合ehcache等等.然后可以set,get方便扩展.
    在这里插入图片描述

    RealmSecurityManager

    RealmSecurityManager内部维护了一个Realm集合,也提供了各种set,get,方便我们扩展.
    在这里插入图片描述

    AuthenticatingSecurityManager

    内部维护了一个认证器,当然也可以set,get,默认提供了个简单的认证器ModularRealmAuthenticator
    在这里插入图片描述

    AuthorizingSecurityManager

    内部维护了一个鉴权器,也有默认的,set,get等.
    在这里插入图片描述

    SessionsSecurityManager

    内部维护了一个session管理器
    在这里插入图片描述

    认证总结

    通过一系列的继承,那这个默认的DefaultSecurityManager就可以使用认证啊,鉴权啊,缓存啊,session啊,real管理啊等各种功能啦!!!
    登录的话,是认证的功能,
    首先通过authenticate方法获取个认证信息authenticate这个方法是认证管理器实现的managerAuthenticatingSecurityManager,使用的认证器去进行认证的,this.authenticator是哪个呢?刚刚说了初始化的时候或设置默认的认证器ModularRealmAuthenticator:
    在这里插入图片描述
    在这里插入图片描述
    然后发现实现里面没有authenticate方法,那就说明,在父类里面,子类里没有的方法就去父类里面找,准没错,父类里的抽象方法,那就去子类里面找实现了
    然后父类AbstractAuthenticator里面又是调用的doAuthenticate,这个的实现是在ModularRealmAuthenticator认证器里面,然后就是判断是单realm还是多realm分别进行认证.:
    在这里插入图片描述
    先看多realm认证的话会判断,是不是要全部通过,才算认证成功,或者是只要一个认证通过,
    file
    再看单个realm认证doSingleRealmAuthentication方法:就是通过realm的getAuthenticationInfo(AuthenticationToken token)方法 AuthenticatingRealm这个实现的:
    file
    我们看看doGetAuthenticationInfo的简单实现,一般是我们自己去实现的.:
    在这里插入图片描述
    在这里插入图片描述
    然后就是进行对比了,默认简单的是通过密码进行equals进行对比的…感兴趣可以看看.
    当然我们也可以自己实现对比器,CredentialsMatcher这个接口,然后set到我们的管理器里面即可;
    对比完成,就是返回认证信息了…
    大体流程,我就把网上图贴上来了:

    怎么进行鉴权(判断是否有权限)的

    鉴权主要就是两个方法,判断是否有对应的角色,判断是否有对应的权限,对应的方法是hasRole跟isPermitted
    这两个方法前面讲过,肯定是通过AuthorizingSecurityManager鉴权管理器进行
    就看isPermitted方法好了.
    代理subject里面实现了isPermitted方法:hasPrincipals方法判断是否登录.是否进行了认证,如果没有进行认证,那判断是否含有权限就没有意义了;
    在这里插入图片描述
    然后就是AuthorizingSecurityManager里的实现,通过使用鉴权器进行鉴权,同理,肯定有初始化的鉴权器的,同样是ModularRealmAuthorizer;认证的是ModularRealmAuthenticator名字都是modularRealm开头,哈哈!
    在这里插入图片描述
    在这里插入图片描述
    ModularRealmAuthorizer
    在这里插入图片描述
    这里的reaml我们就看sampleRealm好了,先看uml图:
    在这里插入图片描述
    AuthorizingRealm->AuthenticatingRealm->CachingReanm想到了啥,是不是跟跟DefaultSecurityManageer有点相似啊,我就不说了,给个眼神自己体会:
    最后就是取出所有权限,然后进行对比,如果有就代表有权限.

    授权

    然后在判断是否含有指定权限之前,肯定要给用户赋予用户该有的权限吧,
    在AuthorizingRealm的各种鉴权方法里面都会先获取用户的鉴权信息getAuthorizationInfo返回AuthorizationInfo
    在这里插入图片描述
    在这里插入图片描述

    总结,以前在使用shiro的回想

    以前做项目的时候总是听别人说,继承AuthorizingRealm然后实现认证,授权两个方法就可以了,shiro就这两个方法,当时也不知道什么原因,只是会用,现在只有通过源码,流程学习,才明白啊!!!
    在这里插入图片描述
    以前也是写个类实现UserDao,其实就是各种操作操作数据库的接口,就是在鉴权里面获取用户啊,权限.等各种信息用的.
    在这里插入图片描述

    世界上所有的不公平都是由于当事人能力不足造成的.
  • 相关阅读:
    Java 抽象类
    Java 多态
    Java 重写与重载
    Java继承
    声卡驱动
    Sublime Text 3快捷键
    近年来世界各地ICO的花式骗局盘点
    区块链未能大爆发的影响因素有哪些?
    BCH分叉是一次站队博弈
    一文读懂百倍币的诞生背景
  • 原文地址:https://www.cnblogs.com/javayida/p/13346788.html
Copyright © 2020-2023  润新知