zoukankan      html  css  js  c++  java
  • shiro身份验证

    身份验证,即在应用中谁能证明他就是他本人。一般提供如他们的身份ID一些标识信息来表明他就是他本人,如提供身份证,用户名/密码来证明。

    在shiro中,用户需要提供principals (身份)和credentials(证明)给shiro,从而应用能验证用户身份:

    principals:身份,即主体的标识属性,可以是任何东西,如用户名、邮箱等,唯一即可。一个主体可以有多个principals,但只有一个Primary principals,一般是用户名/密码/手机号。

    credentials:证明/凭证,即只有主体知道的安全值,如密码/数字证书等。

    最常见的principals和credentials组合就是用户名/密码了。

    例如在AuthenticationToken 就只提供了两个方法,分别获取身份和凭证。AuthenticationToken 的使用的实现一般就是UsernamePasswordToken,但是可以自定义实现,例如JWT token。

    public interface AuthenticationToken extends Serializable {
    
        Object getPrincipal();
        Object getCredentials();
    
    }

    对于身份验证的流程我们同样可以从外部和内部两个角度来看

    一、外部实现流程

    1.、首先准备一些用户身份/凭据(shiro.ini)

    Java代码  
    1. [users]  
    2. zhang=123  
    3. wang=123  

    此处使用ini配置文件,通过[users]指定了两个主体:zhang/123、wang/123。

      

    2、测试用例

    @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、首先通过new IniSecurityManagerFactory并指定一个ini配置文件来创建一个SecurityManager工厂;

    2.2、接着获取SecurityManager并绑定到SecurityUtils,这是一个全局设置,设置一次即可;

    2.3、通过SecurityUtils得到Subject,其会自动绑定到当前线程;如果在web环境在请求结束时需要解除绑定;然后获取身份验证的Token,如用户名/密码;

    2.4、调用subject.login方法进行登录,其会自动委托给SecurityManager.login方法进行登录;

    2.5、如果身份验证失败请捕获AuthenticationException或其子类,常见的如: DisabledAccountException(禁用的帐号)、LockedAccountException(锁定的帐号)、UnknownAccountException(错误的帐号)、ExcessiveAttemptsException(登录失败次数过多)、IncorrectCredentialsException (错误的凭证)、ExpiredCredentialsException(过期的凭证)等,具体请查看其继承关系;对于页面的错误消息展示,最好使用如“用户名/密码错误”而不是“用户名错误”/“密码错误”,防止一些恶意用户非法扫描帐号库;

    2.6、最后可以调用subject.logout退出,其会自动委托给SecurityManager.logout方法退出。

    3.Realm实现

    org.apache.shiro.realm.Realm接口如下: 

    String getName(); //返回一个唯一的Realm名字  
    boolean supports(AuthenticationToken token); //判断此Realm是否支持此Token  
    AuthenticationInfo getAuthenticationInfo(AuthenticationToken token)  
     throws AuthenticationException;  //根据Token获取认证信息 

    自定义Realm实现:

    public class MyRealm1 implements Realm {  
        @Override  
        public String getName() {  
            return "myrealm1";  
        }  
        @Override  
        public boolean supports(AuthenticationToken token) {  
            //仅支持UsernamePasswordToken类型的Token  
            return token instanceof UsernamePasswordToken;   
        }  
        @Override  
        public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {  
            String username = (String)token.getPrincipal();  //得到用户名  
            String password = new String((char[])token.getCredentials()); //得到密码  
            if(!"zhang".equals(username)) {  
                throw new UnknownAccountException(); //如果用户名错误  
            }  
            if(!"123".equals(password)) {  
                throw new IncorrectCredentialsException(); //如果密码错误  
            }  
            //如果身份认证验证成功,返回一个AuthenticationInfo实现;  
            return new SimpleAuthenticationInfo(username, password, getName());  
        }  
    }   

    二、从内部实现原理来看

    流程如下:

    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,将按照相应的顺序及策略进行访问。

    摘自:第二章 身份验证——《跟我学Shiro》

  • 相关阅读:
    【NOIP 2003】 加分二叉树
    【POJ 1655】 Balancing Act
    【HDU 3613】Best Reward
    【POJ 3461】 Oulipo
    【POJ 2752】 Seek the Name, Seek the Fame
    【POJ 1961】 Period
    【POJ 2406】 Power Strings
    BZOJ3028 食物(生成函数)
    BZOJ5372 PKUSC2018神仙的游戏(NTT)
    BZOJ4836 二元运算(分治FFT)
  • 原文地址:https://www.cnblogs.com/xiangkejin/p/8973678.html
Copyright © 2011-2022 走看看