zoukankan      html  css  js  c++  java
  • Shiro浅析:Shiro的登录验证过程

    Shiro浅析:Shiro的登录验证过程

    shiro的登录验证是从Subject.login开始的

    Subject subject = SecurityUtils.getSubject();
    UsernamePasswordToken token = new UsernamePassword(username, password [, remenberme]);
    subject.login(token);
    

    下面来看看Subject的实现类org.apache.shiro.subject.support.DelegatingSubject类的login方法是怎么实现的

    public void login(AuthenticationToken token) throws AuthenticationException {
            clearRunAsIdentitiesInternal();
        	// 代理的SecurityManager
            Subject subject = securityManager.login(this, token);
    		/**……*/
            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的login方法其实是SecurityManger接口实现的DefaultSecurityManager的代理。我们接着往下看DefaultSecurityManager的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;
        }
    
    public AuthenticationInfo authenticate(AuthenticationToken token) throws AuthenticationException {
            return this.authenticator.authenticate(token);
        }
    

    调用Authenticator.authenticate方法获取info,最后到了AbstractAuthenticator类

    if (token == null) {
                throw new IllegalArgumentException("Method argument (authentication token) cannot be null.");
            }
    
            log.trace("Authentication attempt received for token [{}]", token);
    
            AuthenticationInfo info;
            try {
                info = doAuthenticate(token);
                if (info == null) {
                    String msg = "No account information found for authentication token [" + token + "] by this " +
                            "Authenticator instance.  Please check that it is configured correctly.";
                    throw new AuthenticationException(msg);
                }
            } catch (Throwable t) {
            }
    
            log.debug("Authentication successful for token [{}].  Returned account [{}]", token, info);
    
            notifySuccess(token, info);
    
            return info;
    

    我们可以看到一个与重写realm中类似方法doAuthenticate,我们接着问下翻,发现doAuthenticate是来自AbstractAuthenticator的ModularRealmAuthenticator子类

    protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException {
            assertRealmsConfigured();
            Collection<Realm> realms = getRealms();
            if (realms.size() == 1) {
                return doSingleRealmAuthentication(realms.iterator().next(), authenticationToken);
            } else {
                return doMultiRealmAuthentication(realms, authenticationToken);
            }
        }
    

    可以发现这里实际上是获取了我们在Shiro的配置类注册的Realm类,同时对一个或是多个Realm配置执行不同的方法。

    @Bean
        public SecurityManager securityManager() {
            DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
            securityManager.setRealm(loginRealm());
            securityManager.setSessionManager(sessionManager());
            return securityManager;
        }
    

    接下来doSingleRealmAuthentication获取AuthenticationInfo类型的实体, 。而我们重写的realm类也是返回的AuthenticationInfo

    protected AuthenticationInfo doSingleRealmAuthentication(Realm realm, AuthenticationToken token) {
            if (!realm.supports(token)) {
                String msg = "Realm [" + realm + "] does not support authentication token [" +
                        token + "].  Please ensure that the appropriate Realm implementation is " +
                        "configured correctly or that the realm accepts AuthenticationTokens of this type.";
                throw new UnsupportedTokenException(msg);
            }
            AuthenticationInfo info = realm.getAuthenticationInfo(token);
        // 账户错误异常
            if (info == null) {
                String msg = "Realm [" + realm + "] was unable to find account data for the " +
                        "submitted AuthenticationToken [" + token + "].";
                throw new UnknownAccountException(msg);
            }
            return info;
        }
    
    public final AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    		// 尝试从缓存中读取token
            AuthenticationInfo info = getCachedAuthenticationInfo(token);
            if (info == null) {
                //otherwise not cached, perform the lookup:
                
                // 调用自己realm类的doGetAuthenticationInfo
                info = doGetAuthenticationInfo(token);
                log.debug("Looked up AuthenticationInfo [{}] from doGetAuthenticationInfo", info);
                if (token != null && info != null) {
                    cacheAuthenticationInfoIfPossible(token, info);
                }
            } else {
                log.debug("Using cached authentication info [{}] to perform credentials matching.", info);
            }
    
            if (info != null) {
                assertCredentialsMatch(token, info);
            } else {
                log.debug("No AuthenticationInfo found for submitted AuthenticationToken [{}].  Returning null.", token);
            }
    
            return info;
        }
    
    protected abstract AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException;
    

    getAuthenticationInfo来自AuthenticatingRealm类,我们写的realm类也是继承自这个抽象类

  • 相关阅读:
    iOS 中架构模式的浅显理解
    Block 在 ARC 下的拷贝
    Repo 的使用小结
    博客园新语言代码高亮以及OpenLiveWriter插件开发(一)
    GridLayout 使用
    PopupWindow 使用
    NDK笔记(二)-在Android Studio中使用ndk-build
    NDK 笔记(一)
    Java 多线程编程
    搭建Apache Web服务器
  • 原文地址:https://www.cnblogs.com/itcod/p/14917928.html
Copyright © 2011-2022 走看看