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 将可以直接访问,不会跳转到登录页面






  • 相关阅读:
    【译】StackExchange.Redis 中文文档(十)性能分析
    【译】StackExchange.Redis 中文文档(九)服务器相关命令
    【译】StackExchange.Redis 中文文档(八)流
    【译】StackExchange.Redis 中文文档(七)推送/订阅消息顺序
    【译】StackExchange.Redis 中文文档(六)事件
    【译】StackExchange.Redis 中文文档(五)事务
    查看供应商2086报表
    创建内部供应商
    创建客户前台配置
    创建客户后台配置-spro
  • 原文地址:https://www.cnblogs.com/blogxiao/p/8759053.html
Copyright © 2011-2022 走看看