spring 配置 shiro rememberMe


1.shiro 提供記住我的功能,當將form表單中name="rememberMe" 的value設為true或者登陸的token中。token.setRememberMe(true) 的時候,用戶關閉瀏覽器之后,現在進入需要認證的資源的時候就不需要再登陸。

2.form表單中的value不僅僅只有true 的狀態位,還可以設置t、1、enabled、y、yes、on這集中狀態位都表示記住我。

3.登陸頁面login.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>登錄頁面</title>
</head>
<body>
<form action="/shiro/doLogin" >
        <table>
            <tr>
                <td>用戶名:</td>
                <td><input type="text" value="" name="loginName"></td>
            </tr>
            <tr>
                <td>用戶名:</td>
                <td><input type="password" value="" name="password"></td>
            </tr>
            <%--記住我功能--%>
            <tr>
                <td>
                    <%--這里為了方便我默認將value設置為true,shiro對value 的判斷除了true這個狀態位還有:t,1,enabled,y,yes,on這幾種--%>
                    <input type="checkbox" value="true" name="rememberMe">
                </td>
                <td>記住我</td>
            </tr>
        </table>
    <input type="submit" value="登錄">
</form>
</body>
</html>

 

 

 

4.spring 配置rememberMe

  

      <!--rememberMe cookie-->
        <bean id="rememberMe" class="org.apache.shiro.web.servlet.SimpleCookie">
                <constructor-arg  value="rememberMe"></constructor-arg>
                <property name="httpOnly" value="true"></property>
                <!--cookie 的最大失效時間 30天-->
                <property name="maxAge" value="259200"></property>
        </bean>

maxAge=-1 表示關閉瀏覽器cookie失效

 <!--rememberMe 管理器-->
        <bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
                <property name="cipherKey" value="#{T(org.apache.shiro.codec.Base64).decode('4AvVhmFLUs0KTA3Kprsdag==')}"></property>
                <property name="cookie" ref="rememberMe"></property>
        </bean>
cipherKey:表示設置cookie的加密算法,采用的是base64的加密

<!--form表單驗證的過濾器-->
        <bean id="formAuthenticationFilter" class="org.apache.shiro.web.filter.authc.FormAuthenticationFilter">
                <!--loginName 對應form表單的用戶名-->
                <property name="usernameParam" value="loginName" />
                <!--password 對應form表單的密碼-->
                <property name="passwordParam" value="password" />
                <!--rememberMe 記住我checkbox 是否記住我默認為false-->
                <property name="rememberMeParam" value="rememberMe" />
                <!--form 的action-->
                <property name="loginUrl" value="/shiro/doLogin" />
        </bean>

form表單登陸的過濾器,這個過濾器對應的認證key是authc,當登陸的請求匹配到這個key的時候,就將這個過濾器加入到當前請求的過濾器鏈中。

   <!--指定shiro的核心管理器-->
        <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
                <!--可以設置一個或者多個安全域-->
                <property name="realm" ref="customRealm" />
                <!-- 會話管理 -->
                <property name="sessionManager" ref="sessionManager" />
                <!--記住我-->
                <property name="rememberMeManager" ref="rememberMeManager"/>
        </bean>

將rememberMe的管理器交給securityManager 管理。

  <!-- Shiro主過濾器本身功能十分強大,其強大之處就在於它支持任何基於URL路徑表達式的、自定義的過濾器的執行 -->
        <!-- Web應用中,Shiro可控制的Web請求必須經過Shiro主過濾器的攔截,Shiro對基於Spring的Web應用提供了完美的支持 -->
        <!--ShiroFilterFactoryBean 是一個shiroFilter的工廠類,負責實例化過濾器-->
        <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
                <!-- Shiro的核心安全接口,這個屬性是必須的 -->
                <property name="securityManager" ref="securityManager"/>
                <!-- 要求登錄時的鏈接,當request請求被解析為需要認證則跳轉到這個鏈接進行登錄 -->
                <property name="loginUrl" value="/shiro/goLogin"/>
                <!-- 登錄成功后要跳轉的連接(本例中此屬性用不到,因為登錄成功后的處理邏輯在LoginController里硬編碼為main.jsp了) -->
                <!-- <property name="successUrl" value="/system/main"/> -->
                <!-- 用戶訪問未對其授權的資源時,所顯示的連接 -->
                <!-- 若想更明顯的測試此屬性可以修改它的值,如unauthor.jsp,然后用[玄玉]登錄后訪問/admin/listUser.jsp就看見瀏覽器會顯示unauthor.jsp -->
                <property name="unauthorizedUrl" value="/"/>
                <!-- Shiro連接約束配置,即過濾鏈的定義 -->
                <!-- 此處可配合這篇文章來理解各個過濾連的作用http://blog.csdn.net/jadyer/article/details/12172839 -->
                <!-- 下面value值的第一個'/'代表的路徑是相對於HttpServletRequest.getContextPath()的值來的 -->
                <!--shiro的默認過濾器分為兩種:認證過濾器:anon,authcBasic,auchc,user 和授權過濾器:perms,roles,ssl,rest,port-->
                <!-- anon:它對應的過濾器里面是空的,什么都沒做,這里.do和.jsp后面的*表示參數,比方說login.jsp?main這種 -->
                <!-- authc:該過濾器下的頁面必須驗證后才能訪問,它是Shiro內置的一個攔截器org.apache.shiro.web.filter.authc.FormAuthenticationFilter -->
                <!-- user: 表示身份驗證通過,或者記住我-->
                <!-- rememberMe:記住我設置后不用再需要登錄-->
                <property name="filterChainDefinitions">
                        <value>
                                <!--配置記住我攔截-->
                                /shiro/userInfo=user
                              <!--  /mydemo/login=anon
                                /mydemo/getVerifyCodeImage=anon
                                /main**=authc
                                /user/info**=authc
                                /admin/listUser**=authc,perms[admin:manage]-->
                        </value>
                </property>
        </bean>

4.ShiroController.java

 

package com.xiao.core.shiro;

import com.alibaba.druid.sql.visitor.functions.Char;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
@RequestMapping("/shiro")
@Scope("prototype")
public class ShiroController {

    //跳轉到用戶登錄頁面
    @RequestMapping("/goLogin")
    public ModelAndView goLogin(){
        ModelAndView modelAndView=new ModelAndView();
        modelAndView.setViewName("/user/login");
        return modelAndView;
    }

    //用戶登錄請求
    @RequestMapping("/doLogin")
    public ModelAndView doLogin(UserEntity userEntity){
        ModelAndView modelAndView=new ModelAndView();
        String loginName=userEntity.getLoginName();
        String password=userEntity.getPassword();
        //獲取主題
        Subject subject=SecurityUtils.getSubject();

      //創建token
            UsernamePasswordToken token=new UsernamePasswordToken();
            token.setUsername(loginName);
            token.setPassword(password.toCharArray());

            //設置記住我
            token.setRememberMe(true);
            //開始登錄
            subject.login(token);

        

        //判斷是否登錄成功
        if(subject.isAuthenticated()){
            modelAndView.setViewName("/user/loginSuccess"); //登錄成功
        }else{
            modelAndView.setViewName("/user/loginFailed");  //登錄失敗
        }
        return modelAndView;
    }


    /*測試跳轉到下一個頁面是否能繼續使用權限*/
    @RequestMapping("/userInfo")
    public ModelAndView goUserInfo(){
        //獲取用戶的信息
        UserEntity userEntity=(UserEntity) SecurityUtils.getSubject().getPrincipal();
        ModelAndView modelAndView=new ModelAndView();
        modelAndView.setViewName("/user/userInfo");
        /*modelAndView.addObject("user",userEntity);*/
        return modelAndView;
    }

}

UserEntity:用戶實體類

6.啟動server容器之后:

 

 

 點擊登陸之后,當登陸成功之后會調用DefaultSecurityManager的rememberMeSuccessfulLogin方法將記住我寫入到cookie中

 

   protected void rememberMeSuccessfulLogin(AuthenticationToken token, AuthenticationInfo info, Subject subject) {
        RememberMeManager rmm = getRememberMeManager();
        if (rmm != null) {
            try {
                rmm.onSuccessfulLogin(subject, token, info);
            } catch (Exception e) {
                if (log.isWarnEnabled()) {
                    String msg = "Delegate RememberMeManager instance of type [" + rmm.getClass().getName() +
                            "] threw an exception during onSuccessfulLogin.  RememberMe services will not be " +
                            "performed for account [" + info + "].";
                    log.warn(msg, e);
                }
            }
        } else {
            if (log.isTraceEnabled()) {
                log.trace("This " + getClass().getName() + " instance does not have a " +
                        "[" + RememberMeManager.class.getName() + "] instance configured.  RememberMe services " +
                        "will not be performed for account [" + info + "].");
            }
        }
    }

之后再調用RememberManager的onSuccessfulLogin方法

   public void onSuccessfulLogin(Subject subject, AuthenticationToken token, AuthenticationInfo info) {
        //清除上一個subject主題
        forgetIdentity(subject);

        //創建新的認證
        if (isRememberMe(token)) {
            rememberIdentity(subject, token, info);
        } else {
            if (log.isDebugEnabled()) {
                log.debug("AuthenticationToken did not indicate RememberMe is requested.  " +
                        "RememberMe functionality will not be executed for corresponding account.");
            }
        }
    }

繼續跟蹤會到設置cookie 的方法

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


        HttpServletRequest request = WebUtils.getHttpRequest(subject);
        HttpServletResponse response = WebUtils.getHttpResponse(subject);

        //serialized 是princple經過序列化之后的數據,將序列話的數據base64位編碼
        String base64 = Base64.encodeToString(serialized);

        Cookie template = getCookie(); //the class attribute is really a template for the outgoing cookies
        Cookie cookie = new SimpleCookie(template);
        cookie.setValue(base64);
      //設置記住我的cookie cookie.saveTo(request, response); }

7.登陸成功的cookie

.

8.關閉瀏覽器,訪問/shiro/userInfo 將可以直接訪問,不會跳轉到登錄頁面

 

 







免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM