shiro认证登录流程

1、获取从请求中传来的信息(一般是账号和密码),存进UsernamePasswordToken中

UsernamePasswordToken token = new UsernamePasswordToken(username, password)

2、从SecurityUtils中通过getSubject()方法获取登录的主体

Subject subject = SecurityUtils.getSubject();

3、然后执行登录的逻辑

subject.login(token);

4、DelegatingSubject继承与Subject,因此DelegatingSubject重写了Subject的非抽象方法login,如下

 public void login(AuthenticationToken token) throws AuthenticationException {
        clearRunAsIdentitiesInternal();
        Subject subject = securityManager.login(this, token);

        PrincipalCollection principals;

        String host = null;

        if (subject instanceof DelegatingSubject) {
            DelegatingSubject delegating = (DelegatingSubject) subject;
            //we have to do this in case there are assumed identities - we don't want to lose the 'real' principals:
            principals = delegating.principals;
            host = delegating.host;
        } else {
            principals = subject.getPrincipals();
        }

        if (principals == null || principals.isEmpty()) {
            String msg = "Principals returned from securityManager.login( token ) returned a null or " +
                    "empty value.  This value must be non null and populated with one or more elements.";
            throw new IllegalStateException(msg);
        }
        this.principals = principals;
        this.authenticated = true;
        if (token instanceof HostAuthenticationToken) {
            host = ((HostAuthenticationToken) token).getHost();
        }
        if (host != null) {
            this.host = host;
        }
        Session session = subject.getSession(false);
        if (session != null) {
            this.session = decorate(session);
        } else {
            this.session = null;
        }
    }

上述代码中有一句此行代码:Subject subject = securityManager.login(this, token);subject的login方法其实调用的是SecurityManager的login方法
5、SecurityManager的login方法

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
        }

        Subject loggedIn = createSubject(token, info, subject);

        onSuccessfulLogin(token, info, loggedIn);

        return loggedIn;
    }

上述代码中info = authenticate(token);调用的其实是认证器(Authenticator)的认证方法(authenticate),此时由登录(login)转为认证(authenticate),在authenticate方法下调用的是认证器的doAuthenticate方法,如下

 protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException {
        assertRealmsConfigured();
     	//获取Realm的集合,如果只有一个Realm,那么就按照单个流程处理,如果有多个,那么就按照多个流程去认证
        Collection<Realm> realms = getRealms();
        if (realms.size() == 1) {
            return doSingleRealmAuthentication(realms.iterator().next(), authenticationToken);
        } else {
            return doMultiRealmAuthentication(realms, authenticationToken);
        }
    }

6、doSingleRealmAuthentication()方法和doMultiRealmAuthentication()方法
在第5步中获取Realm之后,会按照Realm的数量多少走认证流程,其实此两个方法的底层调用的是Realm的doGetAuthenticationInfo方法,此方法是认证的核心,如果认证成功,则将认证通过的信息装到shiro的AuthenticationInfo(SimpleAuthenticationInfo)中,如果认证失败,则抛出异常。

你可能感兴趣的:(shiro认证登录流程)