zoukankan      html  css  js  c++  java
  • 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的过期后, 需要再去登录.

  • 相关阅读:
    什么是Map 3D 2012/ AIMS2012中的industry model?
    Windows Azure云计算学习笔记1Windows Azure简介
    图解安装Autodesk Infrastructure Map Server(AIMS) 2012
    [转]Fedora8 Linux下安装mapguide
    鼠标手,轨迹球?
    MapGuide Open Source v2.2 快速安装学习指南
    Autodesk云计算云端CAD,AutoCAD WS Android教程
    Isaac的Civil博客.COLIBRA (Civil Objects Library)介绍
    php redis 发布订阅功能(publish/subscribe)
    (转)placement new
  • 原文地址:https://www.cnblogs.com/elvinle/p/9272317.html
Copyright © 2011-2022 走看看