shiro有几种状态,其中包括guest,user,authenticated。guest就是游客,authenticated就是认证后的用户,而user是介于两者之前。user并不代表用户已经成功认证,当用户上次登录时选择rememberMe,下次用户再访问时就是user状态。登录时选择rememberMe,shiro会通过一种加密方式将principal(我们理解为用户名)加密保存到cookie中。shiro可以通过这个cookie解密得到principal。所以当状态为user时,虽然并不代表用户已经通过认证,但我们却可以通过Subject拿到用户名。先贴出代码:
- public void autoLogin(HttpServletRequest request, HttpServletResponse response) {
-
- Subject subject = SecurityUtils.getSubject();
- if(subject.isRemembered()){
- String username = ShiroSecurityHelper.getCurrentUsername();
- LOG.info("用户【{}】自动登录----{}", username,TimeHelper.getCurrentTime());
- User user = userService.getByUsername(username);
- baseLogin(user, request, response);
- ShiroAuthorizationHelper.clearAuthorizationInfo(username); // 用户是自动登录,首先清一下用户权限缓存,让重新加载
- }
- public void baseLogin(User user, HttpServletRequest request, HttpServletResponse response) {
-
- try {
- Subject subject= SecurityUtils.getSubject();
- if (subject.isAuthenticated()) {
- return;
- }
- //如果用户已登录,先踢出
- ShiroSecurityHelper.kickOutUser(user.getUsername());
-
- boolean rememberMe = ServletRequestUtils.getBooleanParameter(request, "rememberMe", false);
- UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword(), rememberMe);
- subject.login(token); // 登录
- } catch (Exception e) {
- //做一些异常处理
- }finally{
- ShiroAuthorizationHelper.clearAuthorizationInfo(sessionUser.getUsername());
- }
- }
ShiroAuthorizationHelper在文章我的shiro之旅: 九 shiro 清理缓存的权限信息有介绍。我们来看看DelegatingSubject类的isRemembered()方法的实现。
- public boolean isRemembered() {
- PrincipalCollection principals = getPrincipals();
- return principals != null && !principals.isEmpty() && !isAuthenticated();
- }
当能拿到principals和用户没认证的时候,这个方法才返回true,principals可以通过cookie解密得到。如果用户是认证状态的,这个方法将返回false。
如此看来,shiro的自动登录实现还是比较简单。
securityManager有个rememberMeManager,用来管理rememberMe的,默认情况下,这个cookie会保存一年时间,我们可以看一下RememberMeManager接口的实现类org.apache.shiro.web.mgt.CookieRememberMeManager的源码:
从构造器中看到cookie.setMaxAge(Cookie.ONE_YEAR);设置cookie的有效时间为一年。也许,这对我们来说会有点长,我们可以更改这些设置。配置如下:
- <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
- <property name="realm" ref="shiroRealm" />
- <!-- <property name="sessionMode" value="native"/> -->
- <property name="cacheManager" ref="shiroCacheManager"/>
- <property name="sessionManager" ref="shiroSessionManager"/>
- <property name="rememberMeManager.cookie.name" value="rememberMe"/>
- <property name="rememberMeManager.cookie.domain" value=".xxx.com"/>
- <property name="rememberMeManager.cookie.path" value="/"/>
- <property name="rememberMeManager.cookie.maxAge" value="604800"/> <!-- 7天有效期 -->
- <!-- <property name="subjectDAO" ref="subjectDAO"/> -->
- </bean>
当然,我们也可以实现自己的rememberMeManager。
|