shiro 獲取請求頭中的 rememberMe

前言:

  上一篇提到了, 將 sessionId 放到請求頭中去, 那rememberMe是否也能夠放到請求頭中去呢.html

  其實無論是sessionId仍是rememberMe, shiro都會默認往cookie裏面放, 那麼rememberMe確定也是能夠放到請求頭中去的.java

  有興趣的朋友能夠去看看 org.apache.shiro.web.mgt.CookieRememberMeManager 的實現. web

  廢話很少說了, 直接上實現吧.spring

一. 實現  

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. 經過瀏覽器登陸, 獲取到rememberMeapache

2. 經過postman, 訪問接口api

 這裏其實有個問題, 之前這裏用cookie的時候, 還能有個cookie的過時時間影響, 好比cookie只保持30天, 那麼過了30天以後, 這個cookie不能再使用了, rememberMe就不能使用了. 瀏覽器

 可是在這裏, 卻沒有這個功能了, 若是想把這個功能加上去, 就必須重寫更多的方法來實現這個功能. cookie

  好比, 咱們能夠將過時時間, 加入到 rememberMe中去, 固然, 必需要通過編碼才行, 不能太明顯. 這樣, 來保證rememberMe的過時後, 須要再去登陸.session

相關文章
相關標籤/搜索