shiro学习10-用户以及登录-登录与退出

<!--[if !supportLists]-->1、    前面已经介绍完了创建subject用户和封装shiro自己的session,这里介绍用户的登录和退出。

 <!--[endif]-->直登录直接调用subject.login(token)方法即可,因为我们在创建subject的时候就把securityManager传入到了subject中,所以subject可以调用securManager的方法,当调用login时,就会调用securityManager会调用里面的login方法。

我们使用的securityManagerDefaultSecurityManager的子类DefaultWebSecurityManager,所以调用的是defaultsecurityManager中的login方法,它里面继续调用了authenticate方法,这个方法的实现在其父类AuthenticatingSecurityManager中,这个类中有一个属性authenticatorAuthenticator类型的,然后在构造方法中会生成一个ModularRealmAuthenticator。这里看一下authenticator类和ModularRealmAuthenticator类。

 

我们看一下他的authenticator的实现AbstractAuthenticator,他的里面有个属性listeners,用户捕获用户的登录失败,登录成功的事件,然后进行相应的处理,当用户退出的时候也会进行通知。

这个类中最重要的方法就是authenticate方法,里面调用了doAuthenticate方法,该方法在ModularRealmAuthenticator类的实现,先看一下这个类的构造方法

public ModularRealmAuthenticator() {

            this.authenticationStrategy = new AtLeastOneSuccessfulStrategy();

      }

 

生成一个登录校验的策略——只要有一个realm校验成功即可。这个是用于多个reaml时才会用到的,如果我们配置了一个realm时不用管他。继续看他的实现的doAuthenticate方法。

扫描二维码关注公众号,回复: 338654 查看本文章

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);

        }

}

里面有个方法getRealms方法,所以我们必须知道他是如何传入的realm,可以在setRealms方法上打上断点然后debug,我们暂时不管它。

他是根据我们配置的realm的个数来区分调用的,因为我们都是只配一个realm,所以我们只看doSingleRealmAuthentication方法即可:

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.";

            thrownew 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 + "].";

            thrownew UnknownAccountException(msg);

        }

        returninfo;

    }

可以发现这个方法就是调用的传入的realmgetAuthenticationInfo方法。

所以现在的关键是得到如何传入的realm。从断点可以发现,在

.RealmSecurityManager.setRealms(Collection<Realm>)这个方法中会执行afterRealmSet方法,而在AuthenticatingSecurityManager.afterRealmsSet()方法中会将传入的realm添加到authenticator(也就是ModularRealmAuthenticator)中,所以我们就明白了校验调用的方法就是传入的realmgetAuthenticationInfo方法。

protectedvoid afterRealmsSet() {

        super.afterRealmsSet();

        if (this.authenticatorinstanceof ModularRealmAuthenticator) {

            ((ModularRealmAuthenticator) this.authenticator).setRealms(getRealms());

        }

}

 

 

<!--[if !supportLists]-->2、     <!--[endif]-->在登陆之后会继续修改产生的subject,添加的属性有isAuthenticatedauthenticationToken。authenticationInfo.在登陆成功之后会将发送的rememberMecookie重新发送,然后将校验通过的信息保存在session.这个在DefaultSecurityManager中的login方法中可以发现。

 

<!--[if !supportLists]-->3、     <!--[endif]-->退出:我也是用debug的方法来查看的org.apache.shiro.subject.support.DelegatingSubject.logout()调用的是这个方法,源码如下:

try {

            clearRunAsIdentitiesInternal();                              

            this.securityManager.logout(this);//调用的还是securityManager,就是创建subject时绑定的securityManager

        } finally {

            this.session = null;

            this.principals = null;

            this.authenticated = false;

        }

我们查看一下调用的securityManagerlogout

        beforeLogout(subject);//这个最终调动的是cookierememberMeManagerforgetIdentity方法,将cookie删掉。

        PrincipalCollection principals = subject.getPrincipals();

        if (principals != null && !principals.isEmpty()) {

            Authenticator authc = getAuthenticator();

            if (authcinstanceof LogoutAware) {

                ((LogoutAware) authc).onLogout(principals);//这个最终调用的是cacherealm中清楚缓存的authenticationInfo的方法,将之前缓存的信息清楚掉,当然我们默认是禁用了验证信息的缓存的。

            }

        }

        try {

            delete(subject);//这个是将把session中缓存的principalCollection和登录状态删掉。

        } catch (Exception e) {

           Xxx

        } finally {

            try {

                stopSession(subject);//这个最终调用的是将httpSeesion销毁,即httpSession.invalidate();

            } catch (Exception e) {

              xxxx

            }

        }

    }

 可以发现,如果用户最后调用了logout,则下一次无法通过cookie获得用户信息了。

猜你喜欢

转载自suichangkele.iteye.com/blog/2276928
今日推荐