Shiro

SpringBoot+Shiro学习(三):Realm认证

2018-08-23  本文已影响15人  Hiwayz

今天我们来讲一下Shiro中最重要的Realm。
自定义Realm通过继承AuthorizingRealm来实现。主要是通过重写两个方法doGetAuthorizationInfo(授权)和doGetAuthenticationInfo(认证)。

我们先来看看身份认证的流程:


image

流程如下:

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

让我们看一段简单的重写

    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //1.从主体传过来的认证信息中,获得用户名
        String username = (String) token.getPrincipal();
        //从数据库读取该用户        
        Users users = userService.getPasswordByUsername(username);
        if(users == null){
            return null;
        }
        String password = users.getPassword();
        //将数据放入info中返回
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username,password,getName());
        //加盐,表示加密的时候加盐加密
        //info.setCredentialsSalt(ByteSource.Util.bytes("Hiway"));
        return info;
    }

AuthenticationInfo

可以从中看到我们用了一个SimpleAuthenticationInfo类,他是继承了AuthenticationInfo:


AuthenticationInfo有两个作用:
1、如果Realm是AuthenticatingRealm子类,则提供给AuthenticatingRealm内部使用的CredentialsMatcher进行凭据验证;(如果没有继承它需要在自己的Realm中自己实现验证);
2、提供给SecurityManager来创建Subject(提供身份信息);

Authenticator及AuthenticationStrategy

Authenticator的职责是验证用户帐号,是Shiro API中身份验证核心的入口点:

public AuthenticationInfo authenticate(AuthenticationToken authenticationToken)  throws AuthenticationException;   

如果验证成功,将返回AuthenticationInfo验证信息;此信息中包含了身份及凭证;如果验证失败将抛出相应的AuthenticationException实现。
SecurityManager接口继承了Authenticator,另外还有一个ModularRealmAuthenticator实现,其委托给多个Realm进行验证,验证规则通过AuthenticationStrategy接口指定,默认提供的实现:

FirstSuccessfulStrategy:只要有一个Realm验证成功即可,只返回第一个Realm身份验证成功的认证信息,其他的忽略;
AtLeastOneSuccessfulStrategy:只要有一个Realm验证成功即可,和FirstSuccessfulStrategy不同,返回所有Realm身份验证成功的认证信息;
AllSuccessfulStrategy:所有Realm验证成功才算成功,且返回所有Realm身份验证成功的认证信息,如果有一个失败就失败了。
ModularRealmAuthenticator默认使用AtLeastOneSuccessfulStrategy策略。


这个authenticate具体是什么情况呢?我们跟进一下:

  1. 一路跟进securityManager,可以看到他继承了AuthenticatingSecurityManager类,该类实现了authenticate方法
    public AuthenticationInfo authenticate(AuthenticationToken token) throws AuthenticationException {
        return this.authenticator.authenticate(token);
    }
  1. 同时在该类创建的时候,就注入了ModularRealmAuthenticator类:
    public AuthenticatingSecurityManager() {
        super();
        this.authenticator = new ModularRealmAuthenticator();
    }
  1. 跟进ModularRealmAuthenticator类,可以看到该类默认是AtLeastOneSuccessfulStrategy策略:
    public ModularRealmAuthenticator() {
        this.authenticationStrategy = new AtLeastOneSuccessfulStrategy();
    }

我们在验证的时候是如何调用到这个authenticate方法呢:

subject.login(token);

跟进可以发现其中的authenticate方法就是调用的AuthenticatingSecurityManager的方法

 public Subject login(Subject subject, AuthenticationToken token) throws AuthenticationException {
        AuthenticationInfo info;
        try {
            info = authenticate(token);
        } catch (AuthenticationException ae) {
            try {
                onFailedLogin(token, ae, subject);
            } catch (Exception e) {
                if (log.isInfoEnabled()) {
                    log.info("onFailedLogin method threw an " +
                            "exception.  Logging and propagating original AuthenticationException.", e);
                }
            }
            throw ae; //propagate
        }
上一篇下一篇

猜你喜欢

热点阅读