zoukankan      html  css  js  c++  java
  • 【shiro】(5)---基于Shiro的权限管理

    基于Shiro的权限管理项目搭建

         前面写了四篇有关权限的文章,算是这篇文章的铺垫了。这篇文章采用 开发环境

              JDK1.8
              Eclipse
              Maven
       技术架构:SpringMVC+Mybatis+jQuery easyUI+Shiro

    一、初步框架搭建

         1、配置web.xml

    <!-- shiro的filter -->
        <!-- shiro过虑器,DelegatingFilterProxy通过代理模式将spring容器中的bean和filter关联起来 -->
        <filter>
            <filter-name>shiroFilter</filter-name>
            <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
            <!-- 设置true由servlet容器控制filter的生命周期 -->
            <init-param>
                <param-name>targetFilterLifecycle</param-name>
                <param-value>true</param-value>
            </init-param>
            <!-- 设置spring容器filter的bean id,如果不设置则找与filter-name一致的bean -->
            <init-param>
                <param-name>targetBeanName</param-name>
                <param-value>shiroFilter</param-value>
            </init-param>
        </filter>
        <filter-mapping>
            <filter-name>shiroFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    shiro过虑器

       2、配置applicationContext-shiro.xml

       我这里把shiro接下来下面要写的配置都写在一起了,方便一起查阅,下面在讲具体的时候还会贴出相关代码。

    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
        xsi:schemaLocation="http://www.springframework.org/schema/beans 
            http://www.springframework.org/schema/beans/spring-beans-3.2.xsd 
            http://www.springframework.org/schema/mvc 
            http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd 
            http://www.springframework.org/schema/context 
            http://www.springframework.org/schema/context/spring-context-3.2.xsd 
            http://www.springframework.org/schema/aop 
            http://www.springframework.org/schema/aop/spring-aop-3.2.xsd 
            http://www.springframework.org/schema/tx 
            http://www.springframework.org/schema/tx/spring-tx-3.2.xsd ">
    
    <!-- web.xml中shiro的filter对应的bean -->
    <!-- Shiro 的Web过滤器 -->
        <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
            <property name="securityManager" ref="securityManager" />
            <!-- loginUrl认证提交地址,如果没有认证将会请求此地址进行认证,请求此地址将由formAuthenticationFilter进行表单认证 -->
            <property name="loginUrl" value="/login.action" />
            
            <!-- 通过unauthorizedUrl指定没有权限操作时跳转页面-->
            <property name="unauthorizedUrl" value="/refuse.jsp" />
            <!-- 自定义filter配置 -->
            <property name="filters">
                <map>
                    <!-- 将自定义 的FormAuthenticationFilter注入shiroFilter中(验证码验证)-->
                    <entry key="authc" value-ref="formAuthenticationFilter" />
                </map>
            </property>
            
            <!-- 过虑器链定义,从上向下顺序执行,一般将/**放在最下边 -->
            <property name="filterChainDefinitions">
                <value>
                    <!-- 对静态资源设置匿名访问 -->
                    /images/** = anon
                    /js/** = anon
                    /styles/** = anon
                    <!-- 验证码,可匿名访问 -->
                    /validatecode.jsp = anon
                    
                    <!-- 请求 logout.action地址(相当于用户点击退出或者注销按钮,shiro去清除session-->
                    /logout.action = logout
                    <!--商品查询需要商品查询权限 ,取消url拦截配置,使用注解授权方式 -->
                    <!-- /items/queryItems.action = perms[item:query]
                    /items/editItems.action = perms[item:edit] -->
                    <!-- 配置记住我或认证通过可以访问的地址 -->
                    /index.jsp  = user
                    /first.action = user
                    /welcome.jsp = user
                    <!-- /** = authc 所有url都必须认证通过才可以访问-->
                    /** = authc
                    <!-- /** = anon所有url都可以匿名访问 -->
                    
                </value>
            </property>
        </bean>
    
    <!-- securityManager安全管理器 -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
            <property name="realm" ref="customRealm" />
            <!-- 注入缓存管理器 -->
            <property name="cacheManager" ref="cacheManager"/>
            <!-- 注入session管理器 -->
            <property name="sessionManager" ref="sessionManager" />
            <!-- 记住我 -->
            <property name="rememberMeManager" ref="rememberMeManager"/> 
            
        </bean>
    
    <!-- realm -->
    <bean id="customRealm" class="com.jincou.shiro.CustomRealm">
        <!-- 将凭证匹配器设置到realm中,realm按照凭证匹配器的要求进行散列 -->
        <property name="credentialsMatcher" ref="credentialsMatcher"/>
    </bean>
    
    <!-- 凭证匹配器 -->
    <bean id="credentialsMatcher"
        class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
        <property name="hashAlgorithmName" value="md5" />
        <property name="hashIterations" value="1" />
    </bean>
    
    <!-- 缓存管理器 -->
    <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
            <property name="cacheManagerConfigFile" value="classpath:shiro-ehcache.xml"/>
        </bean>
    
    <!-- 会话管理器 -->
        <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
            <!-- session的失效时长,单位毫秒 -->
            <property name="globalSessionTimeout" value="600000"/>
            <!-- 删除失效的session -->
            <property name="deleteInvalidSessions" value="true"/>
        </bean>
    
    <!-- 自定义form认证过虑器 -->
    <!-- 基于Form表单的身份验证过滤器,不配置将也会注册此过虑器,表单中的用户账号、密码及loginurl将采用默认值,建议配置 -->
        <bean id="formAuthenticationFilter" 
        class="com.jincou.shiro.CustomFormAuthenticationFilter ">
            <!-- 表单中账号的input名称 -->
            <property name="usernameParam" value="username" />
            <!-- 表单中密码的input名称 -->
            <property name="passwordParam" value="password" />
         <!-- 记住我input的名称 -->
            <property name="rememberMeParam" value="rememberMe"/> 
     </bean>
    
     <!-- rememberMeManager管理器,写cookie,取出cookie生成用户信息 -->
        <bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
            <property name="cookie" ref="rememberMeCookie" />
        </bean>
           <!--   记住我cookie -->
        <bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
            <!-- rememberMe是cookie的名字 -->
            <constructor-arg value="rememberMe" />
            <!-- 记住我cookie生效时间30天 -->
            <property name="maxAge" value="2592000" />
        </bean>
    
    </beans>

        3、自定义CustomRealm

    /**
     * 自定义realm进行认证和授权
     */
    public class CustomRealm extends AuthorizingRealm {
        
        //注入service
        @Autowired
        private SysService sysService;
    
        // 设置realm的名称(名字任意取)
        @Override
        public void setName(String name) {
            super.setName("customRealm");
        }
     
        //realm的认证方法,从数据库查询用户信息
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(
                AuthenticationToken token) throws AuthenticationException {
            
            // token是用户输入的用户名和密码 
            // 第一步从token中取出用户名(为什么前端的用户名直接存到token中呢,
            //因为底层默认获取登陆页面中name等于username的value值,如果不用默认可以在配置文件中修改)
            String userCode = (String) token.getPrincipal();
    
            // 第二步:根据用户输入的userCode从数据库查询
            SysUser sysUser = null;
            try {
                sysUser = sysService.findSysUserByUserCode(userCode);
            } catch (Exception e1) {
                e1.printStackTrace();
            }
            // 如果查询不到返回null
            if(sysUser==null){//
                return null;
            }
            // 从数据库查询到密码
            String password = sysUser.getPassword();      
            //
            String salt = sysUser.getSalt();
    
            // 如果查询到返回认证信息AuthenticationInfo
            //activeUser就是用户身份信息
            ActiveUser activeUser = new ActiveUser();   
            activeUser.setUserid(sysUser.getId());
            activeUser.setUsercode(sysUser.getUsercode());
            activeUser.setUsername(sysUser.getUsername());
            //..
            
            //根据用户id取出菜单
            List<SysPermission> menus  = null;
            try {
                //通过service取出菜单 
                menus = sysService.findMenuListByUserId(sysUser.getId());
            } catch (Exception e) {
                e.printStackTrace();
            }
            //将用户菜单 设置到activeUser
            activeUser.setMenus(menus);
    
            //将activeUser设置simpleAuthenticationInfo
            SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(
                    activeUser, password,ByteSource.Util.bytes(salt), this.getName());
            return simpleAuthenticationInfo;
        }
            
        // 用于授权
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(
                PrincipalCollection principals) {
            
            //从 principals获取主身份信息
            //将getPrimaryPrincipal方法返回值转为真实身份类型(在上边的doGetAuthenticationInfo认证通过填充到SimpleAuthenticationInfo中身份类型),
            ActiveUser activeUser =  (ActiveUser) principals.getPrimaryPrincipal();
            
            //根据身份信息获取权限信息
            //从数据库获取到权限数据
            List<SysPermission> permissionList = null;
            try {
                permissionList = sysService.findPermissionListByUserId(activeUser.getUserid());
            } catch (Exception e) {
                e.printStackTrace();
            }
            //单独定一个集合对象 
            List<String> permissions = new ArrayList<String>();
            if(permissionList!=null){
                for(SysPermission sysPermission:permissionList){
                    //将数据库中的权限标签 符放入集合
                    permissions.add(sysPermission.getPercode());
                }
            }
            
            //查到权限数据,返回授权信息(要包括 上边的permissions)
            SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
            //将上边查询到授权信息填充到simpleAuthorizationInfo对象中
            simpleAuthorizationInfo.addStringPermissions(permissions);
            return simpleAuthorizationInfo;
        }    
        //清除缓存
        public void clearCached() {
            PrincipalCollection principals = SecurityUtils.getSubject().getPrincipals();
            super.clearCache(principals);
        }
    }

    4、controller层拦截登录提交路径

    /**
     * 获得用户名,密码,验证码进行用户验证,验证通过就把该用户放到session中
     */
    @Controller
    public class LoginController {
    
    
    
        //登陆提交地址,和applicationContext-shiro.xml中配置的loginurl一致
        @RequestMapping("login")
        public String login(HttpServletRequest request)throws Exception{
            
            //如果登陆失败从request中获取认证异常信息,shiroLoginFailure就是shiro异常类的全限定名
            String exceptionClassName = (String) request.getAttribute("shiroLoginFailure");
            //根据shiro返回的异常类路径判断,抛出指定异常信息
            if(exceptionClassName!=null){
                if (UnknownAccountException.class.getName().equals(exceptionClassName)) {
                    //最终会抛给异常处理器
                    throw new CustomException("账号不存在");
                } else if (IncorrectCredentialsException.class.getName().equals(
                        exceptionClassName)) {
                    throw new CustomException("用户名/密码错误");
                } else if("randomCodeError".equals(exceptionClassName)){
                    throw new CustomException("验证码错误 ");
                }else {
                    throw new Exception();//最终在异常处理器生成未知错误
                }
            }
            //此方法不处理登陆成功(认证成功),shiro认证成功会自动跳转到上一个请求路径
            //登陆失败还到login页面
            return "login";
        }
    
        //退出
        @RequestMapping(value="/logout" ,method = RequestMethod.POST)
        public String logout(HttpSession httpSession) throws Exception{
            //清空session
            httpSession.invalidate();
            
            return "redirect:first.action";
        }
    }
    LoginController

    5、登录成功后的首页url的controller

         这里主要是看,我的用户数据是如何获得的,原因就是当我通过认证之后,把用户信息放入SimpleAuthenticationInfo对象中,这里只要获取即可。

    @Controller
    //@RequestMapping("/")
    public class FirstAction {
        //系统首页
        @RequestMapping("/first")
        public String first(Model model){
            
            //从shiro中的realm完成认证通过的session中取activeUser
            Subject subject = SecurityUtils.getSubject();
            //取身份信息
            ActiveUser activeUser = (ActiveUser) subject.getPrincipal();
            //通过model传到页面
            model.addAttribute("activeUser", activeUser);
            
            return "/first";
        }    
        //欢迎页面
        @RequestMapping("/welcome")
        public String welcome(Model model){
            
            return "/welcome";        
        }
    }
    controller

    6、退出

      由于使用shiro的sessionManager,不用开发退出功能,使用shiro的logout拦截器即可。

    <!-- 退出拦截,请求logout.action执行退出操作 -->
    /logout.action = logout

    7、无权限refuse.jsp

      当用户无操作权限,shiro将跳转到refuse.jsp页面。

    <!-- 通过unauthorizedUrl指定没有权限操作时跳转页面-->
    <property name="unauthorizedUrl" value="/refuse.jsp" />

    二、认证

    1、添加凭证匹配器

        修改applicationContext-shiro.xml

         添加凭证匹配器实现md5加密校验。(这个之前我是写在ini配置文件中,这里配置在xml文件中)

    <!-- 自定义realm -->
    <bean id="customRealm" class="com.jincou.shiro.CustomRealm">
        <!-- 将凭证匹配器设置到realm中,realm按照凭证匹配器的要求进行散列 -->
        <property name="credentialsMatcher" ref="credentialsMatcher"/>
    </bean>
    
    <!-- 凭证匹配器 -->
    <bean id="credentialsMatcher"
        class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
        <property name="hashAlgorithmName" value="md5" />
        <property name="hashIterations" value="1" />
    </bean>

    2、自定义CustomRealm写认证实现

        这个上面已经写过完整授权认证,具体看上面代码

    三、授权

     1、自定义CustomRealm写认证实现

        修改realm代码从数据库中查询权限信息,将sysService注入realm。(这个代码在上面也放过,具体看上面)

    2、对controller开启AOP

       这个的主要目的是实现对于shiro的注解功能

      在springmvc.xml中配置shiro注解支持,可在controller方法中使用shiro注解配置权限

    (注意在springmvc去掉之前基于URL写的配置的LoginInterceptor和PermissionInterceptor拦截器。因为有shiro就没那个必要了)
     <!-- 开启aop,对类代理 -->
          <aop:config proxy-target-class="true"></aop:config>
    <!-- 开启shiro注解支持 -->
    
    <!-- 需要在上面引入命名空间,和相应jar包 -->
        <!-- 开启aop,对类代理 -->
          <aop:config proxy-target-class="true"></aop:config>
        <!-- 开启shiro注解支持 -->
        <bean
            class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
            <property name="securityManager" ref="securityManager" />
        </bean> 
    配置aop

    3、权限注解控制

       商品查询controller方法添加权限(item:query)

    // 查询商品列表
        @RequestMapping("/queryItem")
        @RequiresPermissions("item:query") // 执行queryItems需要"item:query"权限
        public ModelAndView queryItem() throws Exception {
            // 创建modelAndView准备填充数据、设置视图
            ModelAndView modelAndView = new ModelAndView();
            // 填充数据
            modelAndView.addObject("itemsList", "查看商品页面");
            // 视图
            modelAndView.setViewName("item/itemsList");
            return modelAndView;
        }

       上边代码@RequiresPermissions("item:query")表示必须拥有“item:query”权限方可执行。

       同理,商品修改controller方法添加权限(item:update)

    @RequestMapping(value = "/editItem")
    @RequiresPermissions("item:update")
     public String editItem(@RequestParam(value = "id", required = true) Integer id, Model model) throws Exception

    4、jsp标签控制

      在其它格式的前段页面文件,我还有试过,这里只是.jsp格式文件

      1)Jsp页面添加

    <%@ tagliburi="http://shiro.apache.org/tags" prefix="shiro" %>

     2)标签名称规范

     -- 标签名称                 --标签条件(均是显示标签内容)
    <shiro:authenticated>       --登录之后
    <shiro:notAuthenticated>    --不在登录状态时
    <shiro:guest>               --用户在没有RememberMe时
    <shiro:user>                --用户在RememberMe时
    <shiro:hasAnyRoles name="abc,123" >  --在有abc或者123角色时
    <shiro:hasRole name="abc">           --拥有角色abc
    <shiro:lacksRole name="abc">         --没有角色abc
    <shiro:hasPermission name="abc">     --拥有权限资源abc
    <shiro:lacksPermission name="abc">   --没有abc权限资源
    <shiro:principal>    --显示用户身份名称
     <shiro:principal property="username"/>   --显示用户身份中的属性值

    3)jsp页面添加标签

      如果有商品修改权限页面显示“修改”链接

      <!--代表只有修改权限才会显示-->
    <shiro:hasPermission name="item:update">
        <a href="${pageContext.request.contextPath }/item/editItem.action?id=${item.id}">修改</a>
        </shiro:hasPermission>

    四、缓存

       shiro每次授权都会通过realm获取权限信息,为了提高访问速度需要添加缓存,第一次从realm中读取权限数据,之后不再读取,这里Shiro和Ehcache整合。

    1、配置cacheManager

       在applicationContext-shiro.xml中配置缓存管理器。

    <!-- 安全管理器 -->
        <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
            <property name="realm" ref="userRealm" />
            <property name="cacheManager" ref="cacheManager"/>
        </bean>
    
    <!-- 缓存管理器 -->
    <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
            <property name="cacheManagerConfigFile" value="classpath:shiro-ehcache.xml"/>
        </bean>

    2、配置shiro-ehcache.xml

    <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
        <!--diskStore:缓存数据持久化的目录 地址  -->
        <diskStore path="F:developehcache" />
        <defaultCache 
            maxElementsInMemory="1000" 
            maxElementsOnDisk="10000000"
            eternal="false" 
            overflowToDisk="false" 
            diskPersistent="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120" 
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU">
        </defaultCache>
    </ehcache>
    shiro-ehcache.xml

    3、清空缓存

    当用户权限修改后,用户再次登陆shiro会自动调用realm从数据库获取权限数据,如果在修改权限后想立即清除缓存则可以调用realm的clearCache方法清除缓存。

    (1)CustomRealm中定义clearCached方法

    //清除缓存
        public void clearCached() {
            PrincipalCollection principals = SecurityUtils.getSubject().getPrincipals();
            super.clearCache(principals);
        }

    (2)controller拦截路径调用clearCached方法

    //注入realm
        @Autowired
        private CustomRealm customRealm;
        
        @RequestMapping("/clearShiroCache")
        public String clearShiroCache(){
            
            //清除缓存,将来正常开发要在service调用customRealm.clearCached()
            customRealm.clearCached();
            
            return "success";
        }

    五、session管理

      在applicationContext-shiro.xml中配置sessionManager

    <!-- 安全管理器 -->
        <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
            <property name="realm" ref="userRealm" />
            <property name="sessionManager" ref="sessionManager" />
        </bean>
    <!-- 会话管理器 -->
        <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
            <!-- session的失效时长,单位毫秒 -->
            <property name="globalSessionTimeout" value="600000"/>
            <!-- 删除失效的session -->
            <property name="deleteInvalidSessions" value="true"/>
        </bean>

    六、验证码

    1、自定义FormAuthenticationFilter

    注意:这里验证码是在验证账号密码之前执行的,如果验证码不通过,之前跳过认证和授权的realm,直接跳到controller的路径对于的方法中。

    /**
     * <p>自定义FormAuthenticationFilter,认证之前实现 验证码校验 </p>
     */
    public class CustomFormAuthenticationFilter extends FormAuthenticationFilter {
    
        //原FormAuthenticationFilter的认证方法
        @Override
        protected boolean onAccessDenied(ServletRequest request,ServletResponse response) throws Exception {
            //在这里进行验证码的校验
            
            //从session获取正确验证码
            HttpServletRequest httpServletRequest = (HttpServletRequest) request;
            HttpSession session =httpServletRequest.getSession();
            //取出session的验证码(正确的验证码)
            String validateCode = (String) session.getAttribute("validateCode");
            
            //取出页面的验证码
            //输入的验证和session中的验证进行对比 
            String randomcode = httpServletRequest.getParameter("randomcode");
            if(randomcode!=null && validateCode!=null && !randomcode.equals(validateCode)){
                //如果校验失败,将验证码错误失败信息,通过shiroLoginFailure设置到request中
                httpServletRequest.setAttribute("shiroLoginFailure", "randomCodeError");
                //拒绝访问,不再校验账号和密码 
                return true; 
            }
            //验证码通过,才会到用户认证否则直接到controller层
            return super.onAccessDenied(request, response);
        }        
    }

    2、FormAuthenticationFilter配置

       修改applicationContext-shiro.xml中对FormAuthenticationFilter的配置。

    (1)在shiroFilter中添加filters

    <!-- 自定义filter配置 -->
            <property name="filters">
                <map>
                    <!-- 将自定义 的FormAuthenticationFilter注入shiroFilter中(验证码验证)-->
                    <entry key="authc" value-ref="formAuthenticationFilter" />
                </map>
            </property>
    自定义filter配置

    (2) formAuthenticationFilter定义

    <!-- 自定义form认证过虑器 -->
    <!-- 基于Form表单的身份验证过滤器,不配置将也会注册此过虑器,表单中的用户账号、密码及loginurl将采用默认值,建议配置 -->
        <bean id="formAuthenticationFilter" 
        class="com.jincou.shiro.CustomFormAuthenticationFilter ">
            <!-- 表单中账号的input名称 -->
            <property name="usernameParam" value="username" />
            <!-- 表单中密码的input名称 -->
            <property name="passwordParam" value="password" />
     </bean>
    自定义form认证过虑器

    3、登录页面

       添加验证码

    <TD>验证码:</TD>
        <TD>
    <input id="randomcode" name="randomcode" size="8" /> 
    <img id="randomcode_img" src="${baseurl}validatecode.jsp" alt=""  width="56" height="20" align='absMiddle' />
     <a href=javascript:randomcode_refresh()>刷新</a>
    </TD>
    验证码

    4、配置静态资源文件可以匿名访问

      修改applicationContext-shiro.xml

    <!-- 对静态资源设置匿名访问 -->
        /images/** = anon
        /js/** = anon
        /styles/** = anon
        <!-- 验证码,可匿名访问 -->
        /validatecode.jsp = anon    

    六、记住我

        用户登陆选择“自动登陆”本次登陆成功会向cookie写身份信息,下次登陆从cookie中取出身份信息实现自动登陆。

    1、用户身份实现java.io.Serializable接口

      向cookie记录身份信息需要用户身份信息对象实现序列化接口,如下

    /**
     * 用户身份信息,获取通过用户名得到密码和菜单和页面权限
     */
    public class ActiveUser implements java.io.Serializable {
        /**
         * 
         */
        private static final long serialVersionUID = 1L;
        private String userid;//用户id
        private String usercode;// 用户账号
        private String username;// 用户名称
    
        private List<SysPermission> menus;// 菜单
        private List<SysPermission> permissions;// 权限
    //提供set和get
    }
    ActiveUser实体序列化

    2、配置rememberMeManager

        
    <!-- 安全管理器 -->
        <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
            <property name="realm" ref="userRealm" />
            <property name="sessionManager" ref="sessionManager" />
            <property name="cacheManager" ref="cacheManager"/>
            <!-- 记住我 -->
            <property name="rememberMeManager" ref="rememberMeManager"/>
        </bean>
    
    <!-- rememberMeManager管理器 -->
        <bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
            <property name="cookie" ref="rememberMeCookie" />
        </bean>
        <!-- 记住我cookie -->
        <bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
            <constructor-arg value="rememberMe" />
            <!-- 记住我cookie生效时间30天 -->
            <property name="maxAge" value="2592000" />
        </bean>

    3、FormAuthenticationFilter配置

        修改formAuthenticationFitler添加页面中“记住我checkbox”的input名称

    <bean id="formAuthenticationFilter"
            class="com.jincou.shiro.MyFormAuthenticationFilter">
            <!-- 表单中账号的input名称 -->
            <property name="usernameParam" value="usercode" />
            <!-- 表单中密码的input名称 -->
            <property name="passwordParam" value="password" />
            <property name="rememberMeParam" value="rememberMe"/>
    </bean>

    4、登陆页面

        在login.jsp中添加“记住我”checkbox。

    <tr>
    <td><input type="checkbox" name="rememberMe" />自动登陆</td>
    </tr>

    总结,记住我的流程就相当于把用户序列化储存到本地的cookies文件中,下次要认证的时候,会先到cookies中判断有没有该用户,有就直接来拿,不用在认证。

    5、判断有记住我有没有成功,那么如果成功,在页面的cookies中,会有一个名字为rememberMe的cookies

    代表我的记住我功能成功!

    7、github源码

     https://github.com/yudiandemingzi/shiro_springMVC

  • 相关阅读:
    bzoj2002: [Hnoi2010]Bounce 弹飞绵羊 [分块][LCT]
    luoguP1886 滑动窗口 [单调队列]
    bzoj1047: [HAOI2007]理想的正方形
    bzoj1012: [JSOI2008]最大数maxnumber [单调队列]
    树与二叉树之二--二叉树的性质与存储
    树与二叉树之一--基本概念与存储结构
    Markdown段首空格
    C++ atan2
    凸包学习笔记
    Codeforces Round #545 (Div. 1) E. Train Car Selection
  • 原文地址:https://www.cnblogs.com/qdhxhz/p/9159000.html
Copyright © 2011-2022 走看看