shiro 获取请求头中的 rememberMe

前言:

  上一篇提到了, 将 sessionId 放到请求头中去, 那rememberMe是否也可以放到请求头中去呢.

  其实不管是sessionId还是rememberMe, shiro都会默认往cookie里面放, 那么rememberMe肯定也是可以放到请求头中去的.

  有兴趣的朋友可以去看看 org.apache.shiro.web.mgt.CookieRememberMeManager 的实现. 

  废话不多说了, 直接上实现吧.

一. 实现  

import org.apache.shiro.codec.Base64;
import org.apache.shiro.mgt.AbstractRememberMeManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.subject.SubjectContext;
import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
import org.apache.shiro.web.subject.WebSubjectContext;
import org.apache.shiro.web.util.WebUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class HeaderRememberMeManager extends AbstractRememberMeManager {

    private static final Logger log = LoggerFactory.getLogger(HeaderRememberMeManager.class);

    // header 中 固定使用的 key
    public static final String DEFAULT_REMEMBER_ME_HEADER_NAME = "remember-me";


    @Override
    protected void rememberSerializedIdentity(Subject subject, byte[] serialized) {
        if (!WebUtils.isHttp(subject)) {
            if (log.isDebugEnabled()) {
                String msg = "Subject argument is not an HTTP-aware instance.  This is required to obtain a servlet request and response in order to set the rememberMe cookie. Returning immediately and ignoring rememberMe operation.";
                log.debug(msg);
            }

        } else {
            HttpServletResponse response = WebUtils.getHttpResponse(subject);
            String base64 = Base64.encodeToString(serialized);
            // 设置 rememberMe 信息到 response header 中
            response.setHeader(DEFAULT_REMEMBER_ME_HEADER_NAME, base64);
        }
    }

    private boolean isIdentityRemoved(WebSubjectContext subjectContext) {
        ServletRequest request = subjectContext.resolveServletRequest();
        if (request == null) {
            return false;
        } else {
            Boolean removed = (Boolean) request.getAttribute(ShiroHttpServletRequest.IDENTITY_REMOVED_KEY);
            return removed != null && removed;
        }
    }

    @Override
    protected byte[] getRememberedSerializedIdentity(SubjectContext subjectContext) {
        if (!WebUtils.isHttp(subjectContext)) {
            if (log.isDebugEnabled()) {
                String msg = "SubjectContext argument is not an HTTP-aware instance.  This is required to obtain a servlet request and response in order to retrieve the rememberMe cookie. Returning immediately and ignoring rememberMe operation.";
                log.debug(msg);
            }

            return null;
        } else {
            WebSubjectContext wsc = (WebSubjectContext) subjectContext;
            if (this.isIdentityRemoved(wsc)) {
                return null;
            } else {
                HttpServletRequest request = WebUtils.getHttpRequest(wsc);
                // 在request header 中获取 rememberMe信息
                String base64 = request.getHeader(DEFAULT_REMEMBER_ME_HEADER_NAME);
                if ("deleteMe".equals(base64)) {
                    return null;
                } else if (base64 != null) {
                    base64 = this.ensurePadding(base64);
                    if (log.isTraceEnabled()) {
                        log.trace("Acquired Base64 encoded identity [" + base64 + "]");
                    }

                    byte[] decoded = Base64.decode(base64);
                    if (log.isTraceEnabled()) {
                        log.trace("Base64 decoded byte array length: " + (decoded != null ? decoded.length : 0) + " bytes.");
                    }

                    return decoded;
                } else {
                    return null;
                }
            }
        }
    }

    private String ensurePadding(String base64) {
        int length = base64.length();
        if (length % 4 != 0) {
            StringBuilder sb = new StringBuilder(base64);

            for (int i = 0; i < length % 4; ++i) {
                sb.append('=');
            }

            base64 = sb.toString();
        }

        return base64;
    }

    @Override
    protected void forgetIdentity(Subject subject) {
        if (WebUtils.isHttp(subject)) {
            HttpServletRequest request = WebUtils.getHttpRequest(subject);
            HttpServletResponse response = WebUtils.getHttpResponse(subject);
            this.forgetIdentity(request, response);
        }

    }

    @Override
    public void forgetIdentity(SubjectContext subjectContext) {
        if (WebUtils.isHttp(subjectContext)) {
            HttpServletRequest request = WebUtils.getHttpRequest(subjectContext);
            HttpServletResponse response = WebUtils.getHttpResponse(subjectContext);
            this.forgetIdentity(request, response);
        }
    }

    private void forgetIdentity(HttpServletRequest request, HttpServletResponse response) {
        //设置删除标示
        response.setHeader(DEFAULT_REMEMBER_ME_HEADER_NAME, "deleteMe");
    }
}

 

二. 配置

  <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
        <property name="hashAlgorithmName" value="MD5"/>
        <property name="hashIterations" value="1"/>
        <property name="storedCredentialsHexEncoded" value="true"/>
    </bean>

    <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"/>

    <bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO"/>

    <bean id="rememberMeManager" class="web.shiro.headtoken.HeaderRememberMeManager">
        <property name="cipherKey" value="#{T(org.apache.shiro.codec.Base64).decode('4AvVhmFLUs0KTA3Kprsdag==')}"/>
       <!-- <property name="cookie" ref="rememberMeCookie" />-->
    </bean>

    <bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
        <constructor-arg value="rememberMe"/>
        <property name="httpOnly" value="true"/>
        <property name="maxAge" value="2592000"/><!-- 30天 -->
    </bean>

    <bean id="sessionManager" class="web.shiro.headtoken.DefaultHeaderSessionManager">
        <property name="sessionDAO" ref="sessionDAO"/>
       <!-- <property name="sessionIdCookie" ref="sessionIdCookie"/>-->
        <property name="globalSessionTimeout" value="3600000"/>
        <property name="sessionValidationInterval" value="3600000"/>
    </bean>

    <bean id="shiroRealm" class="web.shiro.ShiroRealm">
        <property name="credentialsMatcher" ref="credentialsMatcher"/>
        <property name="authenticationCachingEnabled" value="true"/>
        <property name="authenticationCacheName" value="authenticationCache"/>
        <property name="authorizationCachingEnabled" value="true"/>
        <property name="authorizationCacheName" value="authorizationCache"/>
    </bean>

    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="sessionManager" ref="sessionManager"/>
        <property name="realm" ref="shiroRealm"/>
        <property name="cacheManager" ref="cacheManager"/>
        <!-- 定义RememberMe的管理器 -->
        <property name="rememberMeManager" ref="rememberMeManager"/>
    </bean>

    <bean name="loginFilter" class="web.shiro.filter.JsonAuthLoginFilter" />
    
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager"/>
        <property name="loginUrl" value="${shiro.loginUrl}"/>
        <property name="filters">
            <map>
                <entry key="login" value-ref="loginFilter" />
            </map>
        </property>
        <property name="filterChainDefinitions">
            <value>
                /logout=logout
                /user/retrievePwd = anon
                /user/signOut = anon
                /user/loginGet = anon
                /swagger-ui.html = anon
                /swagger-resources = anon
                /swagger-resources/** = anon
                /v2/api-docs = anon
                /webjars/** = anon
                /webjars/springfox-swagger-ui/** = anon
                /user/login = anon
                /user/register = anon
                /** = login
            </value>
        </property>
    </bean>

    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
          depends-on="lifecycleBeanPostProcessor"/>

    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager"/>
    </bean>

 

三. 测试方法

1. 通过浏览器登录, 获取到rememberMe

2. 通过postman, 访问接口

 这里其实有个问题, 以前这里用cookie的时候, 还能有个cookie的过期时间影响, 比如cookie只保持30天, 那么过了30天之后, 这个cookie不能再使用了, rememberMe就不能使用了. 

 但是在这里, 却没有这个功能了, 如果想把这个功能加上去, 就必须重写更多的方法来实现这个功能. 

  比如, 我们可以将过期时间, 加入到 rememberMe中去, 当然, 必须要经过编码才行, 不能太明显. 这样, 来保证rememberMe的过期后, 需要再去登录.

posted @ 2018-07-06 11:13  Sniper_ZL  阅读(4792)  评论(0编辑  收藏  举报