zoukankan      html  css  js  c++  java
  • 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 将可以直接访问,不会跳转到登录页面






  • 相关阅读:
    ubuntu 安装 redis desktop manager
    ubuntu 升级内核
    Ubuntu 内核升级,导致无法正常启动
    spring mvc 上传文件,但是接收到文件后发现文件变大,且文件打不开(multipartfile)
    angular5 open modal
    POJ 1426 Find the Multiple(二维DP)
    POJ 3093 Margritas
    POJ 3260 The Fewest Coins
    POJ 1837 Balance(二维DP)
    POJ 1337 A Lazy Worker
  • 原文地址:https://www.cnblogs.com/blogxiao/p/8759053.html
Copyright © 2011-2022 走看看