zoukankan      html  css  js  c++  java
  • 【Shiro学习之二】身份认证

    Apche shiro:1.6.0

    一、重要组件
    1、安全管理器-securityManager
    DefaultSecurityManager:默认安全管理器,用于我们的javaSE安全管理,一般而言用到的少。
    DefaultWebSecurityManager:默认web安全管理器,用于我们的web安全管理;一般而言,我们的应用中初始化此安全管理器。

    2、Subject:与应用程序交互的用户,比如封装输入的用户名和密码信息,然后Subject委托给安全管理器-securityManager。

    对于 Subject 我们一般这么使用:
    (1)身份验证(login)
    (2)授权(hasRole*/isPermitted*或 checkRole*/checkPermission*)
    (3)将相应的数据存储到会话(Session)
    (4)切换身份(RunAs)/多线程身份传播
    (5)退出

    3、Realm:Shiro从Realm 获取安全数据(如用户、 角色、 权限),就是说 SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户与Subject进行比较以确定用户身份是否合法;也需要从 Realm 得到用户相应的角色/权限进行验证用户是否能进行操作;可以把 Realm 看成 DataSource,即安全数据源。
    Shiro提供的Realm清单:

    org.apache.shiro.realm.SimpleAccountRealm 使用配置好的账户进行验证
    org.apache.shiro.realm.text.TextConfigurationRealm 使用文本文件配置的用户权限进行验证
    org.apache.shiro.realm.text.PropertiesRealm 使用.properties文件配置的用户权限进行验证
    org.apache.shiro.realm.text.IniRealm 使用ini文件配置的用户权限进行验证
    org.apache.shiro.realm.ldap.DefaultLdapRealm 使用Ldap进行用户权限验证
    org.apache.shiro.realm.jdbc.JdbcRealm使用数据库方式进行用户权限验证
    org.apache.shiro.realm.activedirectory.ActiveDirectoryRealm 使用active directory LDAP进行身份验证
    org.apache.shiro.realm.AuthorizingRealm 授权类,获取权限角色类信息
    org.apache.shiro.realm.AuthenticatingRealm 身份验证类,获取身份信息
    org.apache.shiro.realm.CachingRealm带有缓存实现的realm

    如果要自定义Realm,继承AuthorizingRealm类就可以了。

    以JdbcRealm为例:

    4、身份验证器-Authenticator
    验证用户帐号,如果验证成功,将返回 AuthenticationInfo 验证信息;此信息中包含了身份及凭证;如果验证失败将抛出相应的 AuthenticationException 实现。

    具体的调用realm进行校验是在ModularRealmAuthenticator里。

    5、AuthenticationStrategy

    对于多个realm时采用AuthenticationStrategy策略进行校验,AuthenticationStrategy接口有三个实现如下,shiro默认AtLeastOneSuccessfulStrategy。
    FirstSuccessfulStrategy:只要有一个 Realm 验证成功即可,只返回第一个 Realm 身份验证成功的认证信息,其他的忽略;
    AtLeastOneSuccessfulStrategy: 只要有一个 Realm 验证成功即可, 和 FirstSuccessfulStrategy不同,返回所有 Realm 身份验证成功的认证信息;
    AllSuccessfulStrategy:所有 Realm 验证成功才算成功,且返回所有 Realm 身份验证成功的认证信息,如果有一个失败就失败了。

    以AtLeastOneSuccessfulStrategy为例展示继承关系:

    6、AuthenticationToken

    AuthenticationToken用于收集用户提交的身份(如用户名)及凭据(如密码);
    扩展接口RememberMeAuthenticationToken:提供了"boolean isRememberMe()"现“记住我”的功能;
    扩展接口HostAuthenticationToken:提供了"String getHost()"方法用于获取用户“主机”的功能;
    UsernamePasswordToken:简单的用户名和密码;
    CasToken:单点登录相关令牌;
    BearerToken:包含一个承载令牌或API密钥,通常通过HTTP报头接收。

    7、PrincipalCollection

    我们可以在Shiro中同时配置多个Realm,所以呢身份信息可能就有多个; 因此其提供了 PrincipalCollection 用于聚合这些身份信息.

    public interface PrincipalCollection extends Iterable, Serializable { 
        Object getPrimaryPrincipal(); //得到主要的身份 
        <T> T oneByType(Class<T> type); //根据身份类型获取第一个 
        <T> Collection<T> byType(Class<T> type); //根据身份类型获取一组 
        List asList(); //转换为 List 
        Set asSet(); //转换为 Set 
        Collection fromRealm(String realmName); //根据 Realm 名字获取 
        Set<String> getRealmNames(); //获取所有身份验证通过的 Realm 名字 
        boolean isEmpty(); //判断是否为空 
    } 

    因为PrincipalCollection 聚合了多个, 此处最需要注意的是 getPrimaryPrincipal, 如果只有一 个 Principal 那么直接返回即可,如果有多个 Principal,则返回第一个(因为内部使用 Map 存储,所以可以认为是返回任意一个);oneByType / byType 根据凭据的类型返回相应的 Principal;fromRealm 根据 Realm 名字(每个 Principal 都与一个 Realm 关联)获取相应的 Principal。

    目前Shiro只提供了一个实现SimplePrincipalCollection, 还记得之前的AuthenticationStrategy 实现嘛,用于在多 Realm 时判断是否满足条件的,在大多数实现中(继承了 AbstractAuthenticationStrategy ) afterAttempt 方 法 会 进 行 AuthenticationInfo ( 实 现 了 MergableAuthenticationInfo)的 merge,比如 SimpleAuthenticationInfo 会合并多个 Principal 为一个 PrincipalCollection。

    8、AuthenticationInfo

    AuthenticationInfo 有两个作用:
    (1)如果 Realm 是 AuthenticatingRealm 子类,则提供给 AuthenticatingRealm 内部使用的CredentialsMatcher 进行凭据验证;(如果没有继承它需要在自己的 Realm中自己实现验证) ;
    (2)提供给 SecurityManager 来创建 Subject(提供身份信息);
    MergableAuthenticationInfo 用于提供在多 Realm 时合并 AuthenticationInfo 的功能,主要合并Principal、如果是其他的如 credentialsSalt,会用后边的信息覆盖前边的。 比如HashedCredentialsMatcher 在验证时会判断AuthenticationInfo是否是SaltedAuthenticationInfo子类,来获取盐信息。
    Account相当于我们之前的User, SimpleAccount是其一个实现;
    在IniRealm、 PropertiesRealm这种静态创建帐号信息的场景中使用,这些Realm直接继承了SimpleAccountRealm,而SimpleAccountRealm 提供了相关的 API 来动态维护 SimpleAccount;即可以通过这些 API来动态增删改查SimpleAccount;动态增删改查角色/权限信。
    其他情况一般返回 SimpleAuthenticationInfo 即可

    二、身份认证流程

    1、代码示例

    @Test
        public void testHelloworld() {
            //1、获取SecurityManager工厂,此处使用Ini配置文件初始化SecurityManager
            Factory<org.apache.shiro.mgt.SecurityManager> factory =
                    new IniSecurityManagerFactory("classpath:shiro.ini");
    
            //2、得到SecurityManager实例 并绑定给SecurityUtils
            org.apache.shiro.mgt.SecurityManager securityManager = factory.getInstance();
            SecurityUtils.setSecurityManager(securityManager);
    
            //3、得到Subject及创建用户名/密码身份验证Token(即用户身份/凭证)
            Subject subject = SecurityUtils.getSubject();
            UsernamePasswordToken token = new UsernamePasswordToken("zhang", "123");
    
            try {
                //4、登录,即身份验证
                subject.login(token);
            } catch (AuthenticationException e) {
                //5、身份验证失败
            }
    
            Assert.assertEquals(true, subject.isAuthenticated()); //断言用户已经登录
    
            //6、退出
            subject.logout();
        }

    2、图示流程

    (1)首先调用 Subject.login(token)进行登录,其会自动委托给 Security Manager,调用之前必须通过 SecurityUtils. setSecurityManager()设置; 
    (2)SecurityManager 负责真正的身份验证逻辑;它会委托给 Authenticator 进行身份验证; 
    (3)Authenticator 才是真正的身份验证者,Shiro API 中核心的身份认证入口点,此处可以自定义插入自己的实现; 
    (4)Authenticator 可能会委托给相应的 AuthenticationStrategy 进行多 Realm 身份验证,默认ModularRealmAuthenticator 会调用 AuthenticationStrategy 进行多 Realm 身份验证; 
    (5)Authenticator 会把相应的 token 传入 Realm,从 Realm 获取身份验证信息,如果没有返回/抛出异常表示身份验证失败了。此处可以配置多个 Realm,将按照相应的顺序及策略进行访问。 


    3、源码流程分析

    Subject::login
    -->DelegatingSubject::login
    -->securityManager::login
    -->DefaultSecurityManager::login(对于javase应用)
    -->AuthenticatingSecurityManager::authenticate
    -->AbstractAuthenticator::authenticate
    -->ModularRealmAuthenticator::doAuthenticate 在这里会获取所有的realm
    如果只有一个realm,就调用realm的getAuthenticationInfo进行身份验证;
    如果是多个realm,先获取验证策略:ModularRealmAuthenticator::getAuthenticationStrategy
    -->然后再根据策略调用realm的getAuthenticationInfo方法进行验证

    小结:在配置时,要选择正确的安全管理器,并自定义好自己的认证方式Realm,如果是多个Relam,则要设置好相应的验证策略。

  • 相关阅读:
    游戏人生Silverlight(2) 趣味钢琴[Silverlight 2.0(c#)]
    稳扎稳打Silverlight(35) 3.0控件之ChildWindow, SaveFileDialog, HeaderedItemsControl, VirtualizingStackPanel
    Silverlight 3.0 Demo
    稳扎稳打Silverlight(34) 3.0控件之Frame, Page, Label, DescriptionViewer, ValidationSummary
    再接再厉VS 2008 sp1 + .NET 3.5 sp1系列文章索引
    稳扎稳打Silverlight(37) 3.0动画之Easing(缓动效果)
    返璞归真 asp.net mvc (1) 添加、查询、更新和删除的 Demo
    返璞归真 asp.net mvc (2) 路由(System.Web.Routing)
    游戏人生Silverlight(5) 星际竞技场[Silverlight 2.0(c#, Farseer Physics Engine)]
    稳扎稳打Silverlight(30) 2.0Tip/Trick之Silverlight.js, Silverlight.supportedUserAgent.js, 自定义启动界面, 响应鼠标滚轮事件
  • 原文地址:https://www.cnblogs.com/cac2020/p/13819433.html
Copyright © 2011-2022 走看看