zoukankan      html  css  js  c++  java
  • Shiro笔记(二)身份验证

    Shiro笔记(二)身份验证

    一、核心代码

     1 @Test
     2     public void helloWorldTest(){
     3         IniSecurityManagerFactory factory =
     4                 new IniSecurityManagerFactory("classpath:shiro-jdbc-realm.ini");
     5         SecurityManager manager = factory.getInstance();
     6        //全局设置,一次即可
     7         SecurityUtils.setSecurityManager(manager);
     8         Subject subject = SecurityUtils.getSubject();
     9         UsernamePasswordToken token =
    10                 new UsernamePasswordToken("Peter", "123");
    11         try{
    12                subject.login(token);
    13             }catch (AuthenticationException e){
    14                 e.printStackTrace();
    15             }
    16 
    17         Assert.assertEquals(true,subject.isAuthenticated());
    18         //退出登录
    19         subject.logout();

    shiro.ini文件:

    [users]
    Peter=123
    Tom=321

    二、身份认证流程:

    Authenticator 可能会委托给相应的 AuthenticationStrategy 进行多 Realm 身份验证,默认
    ModularRealmAuthenticator 会调用 AuthenticationStrategy 进行多 Realm 身份验证;
    Authenticator 会把相应的 token 传入 Realm,从 Realm 获取身份验证信息

     三、Realm

    Shiro 从从 Realm 获取安全数据(如用户、角色、权限)

    Reaml接口:

    1 public interface Realm {
    2     //获得唯一的名字
    3     String getName();
    4     //判断此realm是否支持此token
    5     boolean supports(AuthenticationToken token);
    6     //获取token认证信息
    7     AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException;
    8 }

    一)单Realm配置

     1 public class MyRealm implements Realm{
     2 
     3     public String getName() {
     4         return "myRealm";
     5     }
     6 
     7     public boolean supports(AuthenticationToken authenticationToken) {
     8         //仅支持UsernamePasswordToken类型
     9         return authenticationToken instanceof UsernamePasswordToken;
    10     }
    11 
    12     public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    13         //获取用户名
    14         String username= (String) token.getPrincipal();
    15         //获取密码
    16         String password=new String((char[]) token.getCredentials());
    17         if(!"Peter".equals(username)){
    18             throw new UnknownAccountException();
    19         }
    20         if(!"123".equals(password)){
    21             throw new IncorrectCredentialsException();
    22         }
    23         return new SimpleAuthenticationInfo(username,password,getName());
    24     }
    25 }

    ini文件指定:

    1 myRealm=com.tang.shirotest.LoginLogoutTest
    2 securityManager.realms=$myRealm

    二)JDBC Realm的使用

    1 [main]
    2 jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm
    3 dataSource=com.alibaba.druid.pool.DruidDataSource
    4 dataSource.driverClassName=com.mysql.jdbc.Driver
    5 dataSource.url=jdbc:mysql://localhost:3306/shiro
    6 dataSource.username=root
    7 dataSource.password=jiapi1990
    8 jdbcRealm.dataSource=$dataSource
    9 securityManager.realms=$jdbcRealm

    三)Authenticator及AuthenticationStrategy

    Authenticator的职责是验证用户账号,接口为:

    public interface Authenticator {
        AuthenticationInfo authenticate(AuthenticationToken var1) throws AuthenticationException;
    }

    SecurityManager 接口继承了 Authenticator,另外还有一个 ModularRealmAuthenticator 实现,
    其委托给多个 Realm 进行验证,验证规则通过 AuthenticationStrategy 接口指定,默认提供
    的实现:
    FirstSuccessfulStrategy:只要有一个 Realm 验证成功即可,只返回第一个 Realm 身份验证
    成功的认证信息,其他的忽略;
    AtLeastOneSuccessfulStrategy:只要有一个 Realm 验证成功即可,和 FirstSuccessfulStrategy
    不同,返回所有 Realm 身份验证成功的认证信息;
    AllSuccessfulStrategy:所有 Realm 验证成功才算成功,且返回所有 Realm 身份验证成功的
    认证信息,如果有一个失败就失败了

    ModularRealmAuthenticator 默认使用 AtLeastOneSuccessfulStrategy 策略。

    ini文件:

     1 #指定 securityManager 的 authenticator 实现
     2 authenticator=org.apache.shiro.authc.pam.ModularRealmAuthenticator
     3 securityManager.authenticator=$authenticator
     4 #指定 securityManager.authenticator 的 authenticationStrategy
     5 allSuccessfulStrategy=org.apache.shiro.authc.pam.AllSuccessfulStrategy
     6 securityManager.authenticator.authenticationStrategy=$allSuccessfulStrategy
     7 myRealm1=com.github.zhangkaitao.shiro.chapter2.realm.MyRealm1
     8 myRealm2=com.github.zhangkaitao.shiro.chapter2.realm.MyRealm2
     9 myRealm3=com.github.zhangkaitao.shiro.chapter2.realm.MyRealm3
    10 securityManager.realms=$myRealm1,$myRealm3

    AuthenticationStrategy接口:

     1 public interface AuthenticationStrategy {
     2     //在所有 Realm 验证之前调用
     3     AuthenticationInfo beforeAllAttempts(Collection<? extends Realm> realms, AuthenticationToken token) throws AuthenticationException;
     4     //在每个 Realm 之前调用
     5     AuthenticationInfo beforeAttempt(Realm realm, AuthenticationToken token, AuthenticationInfo aggregate) throws AuthenticationException;
     6     //在每个 Realm 之后调用
     7     AuthenticationInfo afterAttempt(Realm realm, AuthenticationToken token, AuthenticationInfo singleRealmInfo, AuthenticationInfo aggregateInfo, Throwable t)
     8             throws AuthenticationException;
     9     ////在所有 Realm 之后调用
    10     AuthenticationInfo afterAllAttempts(AuthenticationToken token, AuthenticationInfo aggregate) throws AuthenticationException;
    11 }

    自定义实现:

     1 public class AtLeastTwoAuthenticatorStrategy extends AbstractAuthenticationStrategy {
     2 
     3     @Override
     4     public AuthenticationInfo beforeAllAttempts(Collection<? extends Realm> realms, AuthenticationToken token) throws AuthenticationException {
     5         return new SimpleAuthenticationInfo();//返回一个权限的认证信息
     6     }
     7 
     8     @Override
     9     public AuthenticationInfo beforeAttempt(Realm realm, AuthenticationToken token, AuthenticationInfo aggregate) throws AuthenticationException {
    10         return aggregate;//返回之前合并的
    11     }
    12 
    13     @Override
    14     public AuthenticationInfo afterAttempt(Realm realm, AuthenticationToken token, AuthenticationInfo singleRealmInfo, AuthenticationInfo aggregateInfo, Throwable t) throws AuthenticationException {
    15         AuthenticationInfo info;
    16         if (singleRealmInfo == null) {
    17             info = aggregateInfo;
    18         } else {
    19             if (aggregateInfo == null) {
    20                 info = singleRealmInfo;
    21             } else {
    22                 info = merge(singleRealmInfo, aggregateInfo);
    23             }
    24         }
    25 
    26         return info;
    27     }
    28 
    29     @Override
    30     public AuthenticationInfo afterAllAttempts(AuthenticationToken token, AuthenticationInfo aggregate) throws AuthenticationException {
    31         if (aggregate == null || CollectionUtils.isEmpty(aggregate.getPrincipals()) || aggregate.getPrincipals().getRealmNames().size() < 2) {
    32             throw new AuthenticationException("Authentication token of type [" + token.getClass() + "] " +
    33                     "could not be authenticated by any configured realms.  Please ensure that at least two realm can " +
    34                     "authenticate these tokens.");
    35         }
    36 
    37         return aggregate;
    38     }
    39 }
    Simple is important!
  • 相关阅读:
    ParamCount、ParamStr
    写一个可拖动的 TShape 回复 "韦韦" 的问题
    读十六进制文本到 Btye 数组的函数 回复 "峰哥!!!" 的问题
    网站速度优化
    [新功能]新增分类浏览页面
    [CN.Text开发笔记]嵌套Repeater的问题
    中秋祝福
    10 Golden rules for publishing your blog
    HttpCompressionModule 6的一个Bug及使用效果
    [CN.Text开发笔记]OnInit与运行期数据绑定
  • 原文地址:https://www.cnblogs.com/Shadowplay/p/7674937.html
Copyright © 2011-2022 走看看