shiro授权,自定义realm实现授权,shiro与项目集成,在项目中实现认证及授权

讲前必读

第一节:shiro授权

1. 重点:讲解授权流程并实现对用户授权。

2. 课程实际内容

a)    简介:回顾shiro架构及相关对象以及认证流程

b)    重点:shiro授权流程

c)     简介:授权方式

d)    重点:授权实现

e)    简介:测试

3. 重点:课堂总结

a)    授权实现

练习20分钟

第二节:自定义Realm实现授权

1. 重点:自定义Realm实现授权。

2. 课程实际内容

a) 简介:配置文件实现授权的缺点

b) 重点:通过自定义Realm实现动态授权

c) 重点:自定义Realm实现授权步骤

d) 简介:测试

3. 重点:课堂总结

a) 自定义Realm实现授权步骤

第三节:shiro与项目集成开发

1. 重点:shiro整合spring web要点

2. 课程实际内容

a)    简介:shiro整合web项目的必要性

b)    重点:在项目整合shiro

c)    简介:shiro过滤器

d)    重点:通过shiro实现登录

e)    简介:通过shiro实现退出

3. 重点:课堂总结

a)    Shiro整合项目的步骤

第四节:在集成项目中实现认证及授权

1. 重点:如何在集成项目实现授权,Controller中如何控制,jsp中如何控制

2. 课程实际内容

a)    重点:认证实现

b)    重点:修改自定义Realm

c)    重点:权限注解控制

d)    重点:jsp标签控制

3. 重点:课堂总结

a) 项目中认证和授权的实现步骤及对比之前学习的认证和授权

练习30分钟

第五节:缓存管理、验证码及记住我实现

1. 重点:缓存管理的必要性及缓存管理的实现

2. 课程实际内容

a)    简介:为什么需要缓存管理

b)  重点:缓存管理的实现

c)    重点:验证码实现

d)    简介:记住我实现

3. 重点:课堂总结

a) 总结缓存管理的好处。

 

 

第一节课备课参考

核心脉络

授权在整个权限管理中的重要性,shiro中的授权流程,如何实现授权,如何在自定义Realm中实现授权。

重点:

1.    在自定义Realm中实现授权

 

难点:

1.  在自定义Realm中实现授权

 

互动:在前一天的课程中,实现了权限管理中的身份认证,接下来讨论另外一个非常重要的点------授权。

授权

授权,也叫访问控制,即在应用中控制谁能访问哪些资源(如访问页面/编辑数据/页面操作

等)。在授权中需了解的几个关键对象:主体(Subject)、资源(Resource)、权限(Permission)、

角色(Role)。

关键对象介绍

主体

主体,即访问应用的用户,在Shiro中使用Subject代表该用户。用户只有授权后才允许访

问相应的资源。

资源

在应用中用户可以访问的任何东西,比如访问JSP 页面、查看/编辑某些数据、访问某个业

务方法、打印文本等等都是资源。用户只要授权后才能访问。

权限

安全策略中的原子授权单位,通过权限我们可以表示在应用中用户有没有操作某个资源的

权力。即权限表示在应用中用户能不能访问某个资源,如:访问用户列表页面查看/新增/修改/删除用户数据(即很多时候都是CRUD(增查改删)式权限控制)打印文档等等。。。

角色

角色代表了操作集合,可以理解为权限的集合,一般情况下我们会赋予用户角色而不是权

限,即这样用户可以拥有一组权限,赋予权限时比较方便。典型的如:项目经理、技术总

监、CTO、开发工程师等都是角色,不同的角色拥有一组不同的权限。

 

授权流程

流程如下:

1、首先调用Subject.isPermitted*/hasRole*接口,其会委托给SecurityManager,而

SecurityManager接着会委托给Authorizer;

2、Authorizer是真正的授权者,如果我们调用如isPermitted(“user:view”),其首先会通过

PermissionResolver把字符串转换成相应的Permission实例;

3、在进行授权之前,其会调用相应的Realm获取Subject相应的角色/权限用于匹配传入的

角色/权限;

4、Authorizer会判断Realm的角色/权限是否和传入的匹配,如果有多个Realm,会委托给

ModularRealmAuthorizer进行循环判断,如果匹配如isPermitted*/hasRole*会返回true,否

则返回false表示授权失败。

授权方式

Shiro支持三种方式的授权:

编程式:通过写if/else授权代码块完成:

Subject subject = SecurityUtils.getSubject();

if(subject.hasRole(“admin”)) {

//有权限

} else {

//无权限

}

注解式:通过在执行的Java方法上放置相应的注解完成:

@RequiresRoles("admin")

public void hello() {

//有权限

}

没有权限将抛出相应的异常;

JSP/GSP 标签:在JSP/GSP 页面通过相应的标签完成:

 

授权实现

在ini配置文件配置用户拥有的角色及角色-权限关系(shiro-permission.ini)

[users]

zhangsan=1111,role1,role2

lisi=1111,role1

[roles]

role1=user:create,user:update

role2=user:create,user:delete

 

规则:“用户名=密码,角色1,角色2” “角色=权限1,权限2”,即首先根据用户名找

到角色,然后根据角色再找到权限;即角色是权限集合;Shiro 同样不进行权限的维护,需

要我们通过Realm返回相应的权限信息。只需要维护“用户——角色”之间的关系即可。

 

权限字符串的规则是:“资源标识符:操作:资源实例标识符”,意思是对哪个资源的哪个实例具有什么操作,“:”是资源/操作/实例的分割符,权限字符串也可以使用*通配符。

 

例子:

用户创建权限:user:create,或user:create:*

用户修改实例001的权限:user:update:001

用户实例001的所有权限:user:*:001

实现代码

/**

 *

 * @author邹波

 * @version 1.0

 * @date 2016-1-21

 */

public class ShiroTest {

   //用户登录和退出

   @Test

   public void testPermission(){

      // 构建SecurityManager工厂,IniSecurityManagerFactory可以从ini文件中初始化SecurityManager环境

      Factory factory = new IniSecurityManagerFactory("classpath:shiro-permission.ini");

      //通过工厂获得SecurityManager实例

      SecurityManager securityManager = factory.getInstance();

      //将securityManager设置到运行环境中

      SecurityUtils.setSecurityManager(securityManager);

      //获取subject实例

      Subject subject = SecurityUtils.getSubject();

      //创建用户名,密码身份验证Token

      UsernamePasswordToken token = new UsernamePasswordToken("zhangsan", "1111");

      try {

         //登录,即身份验证

         subject.login(token);

      } catch (AuthenticationException e) {

         e.printStackTrace();

         //身份认证失败

      }

      // 用户认证状态

      boolean isAuthenticated = subject.isAuthenticated();

      System.out.println("用户认证状态:" + isAuthenticated);

     

      //判断拥有角色:role1

      Assert.assertTrue(subject.hasRole("role1"));

      //判断拥有角色:role1 and role2

      Assert.assertTrue(subject.hasAllRoles(Arrays.asList("role1", "role2")));

      //判断拥有角色:role1 and role2 and !role3

      boolean[] result = subject.hasRoles(Arrays.asList("role1", "role2", "role3"));

      Assert.assertEquals(true, result[0]);

      Assert.assertEquals(true, result[1]);

      Assert.assertEquals(false, result[2]);

     

     

      //判断拥有权限:user:create

      Assert.assertTrue(subject.isPermitted("user:create"));

      //判断拥有权限:user:update and user:delete

      Assert.assertTrue(subject.isPermittedAll("user:update", "user:delete"));

      //判断没有权限:user:view

      Assert.assertFalse(subject.isPermitted("user:view"));

   }

}

 

 

第二节课备课参考

核心脉络

通过自定义Realm实现动态授权。

重点:

1. 自定义Realm实现

 

难点:

1. 自定义Realm实现

自定义Realm实现授权

与上边认证自定义realm一样,大部分情况是要从数据库获取权限数据,这里直接实现基于资源的授权。

UserRealm实现代码

/**

 * 自定义Realm实现

 * @author邹波

 * @version 1.0

 * @date 2016-1-21

 */

public class UserRealm extends AuthorizingRealm {

   @Override

   public String getName() {

      return "UserRealm";

   }

   //用于认证

   @Override

   protected AuthenticationInfo doGetAuthenticationInfo(

         AuthenticationToken token) throws AuthenticationException {

      //从token中获取身份信息

      String username = (String)token.getPrincipal();

      //根据用户名到数据库中取出用户信息  如果查询不到 返回null

      String password = "1111";//假如从数据库中获取密码为1111

      //返回认证信息

      SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(username, password, this.getName());

      return simpleAuthenticationInfo;

   }

   //用于授权

   @Override

   protected AuthorizationInfo doGetAuthorizationInfo(

         PrincipalCollection principals) {

      //获取身份信息

      String username = (String)principals.getPrimaryPrincipal();

      //根据身份信息获取权限数据

      //模拟

      List permissions = new ArrayList();

      permissions.add("user:save");

      permissions.add("user:delete");

      //将权限信息保存到AuthorizationInfo

      SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();

      for(String permission:permissions){

         simpleAuthorizationInfo.addStringPermission(permission);

      }

      return simpleAuthorizationInfo;

   }

}

增加了红色部分代码

配置文件

[main]

#自定义 realm

userRealm=cn.siggy.realm.UserRealm

#将realm设置到securityManager

securityManager.realms=$userRealm

测试代码

/**

 * 自定义Realm实现

 * @author邹波

 * @version 1.0

 * @date 2016-1-21

 */

public class UserRealm extends AuthorizingRealm {

   @Override

   public String getName() {

      return "UserRealm";

   }

   //用于认证

   @Override

   protected AuthenticationInfo doGetAuthenticationInfo(

         AuthenticationToken token) throws AuthenticationException {

      //从token中获取身份信息

      String username = (String)token.getPrincipal();

      //根据用户名到数据库中取出用户信息  如果查询不到 返回null

      String password = "1111";//假如从数据库中获取密码为1111

      //返回认证信息

      SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(username, password, this.getName());

      return simpleAuthenticationInfo;

   }

   //用于授权

   @Override

   protected AuthorizationInfo doGetAuthorizationInfo(

         PrincipalCollection principals) {

      //获取身份信息

      String username = (String)principals.getPrimaryPrincipal();

      //根据身份信息获取权限数据

      //模拟

      List permissions = new ArrayList();

      permissions.add("user:save");

      permissions.add("user:update");

      permissions.add("user:delete");

      //将权限信息保存到AuthorizationInfo

      SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();

      for(String permission:permissions){

         simpleAuthorizationInfo.addStringPermission(permission);

      }

      return simpleAuthorizationInfo;

   }

}

 

测试

第三节课备课参考

核心脉络

在之前的学习中,虽然学习了shiro架构中非常重要的几块知识,但是只是在java SE项目中使用。那么如何在集成项目中使用shiro,是接下来我们要去讨论的问题。

重点:

1. 在spring web中整合shiro

 

难点:

1. 在spring web中整合shiro

 

互动:在这之前我们把shiro的相关技术点已经弄完了。那么接下来我们看看在项目中如何使用shiro。

shiro与项目集成开发

shiro与spring web项目整合

         shiro与springweb项目整合在“基于url拦截实现的工程”基础上整合,基于url拦截实现的工程的技术架构是springmvc+mybatis,整合注意两点:

         1、shiro与spring整合

         2、加入shiro对web应用的支持

 

取消原springmvc认证和授权拦截器

去掉springmvc.xml中配置的LoginInterceptor和PermissionInterceptor拦截器。

 

加入shiro的 jar包

 

web.xml添加shiro Filter

    <filter>

        <filter-name>shiroFilterfilter-name>

        <filter-class>org.springframework.web.filter.DelegatingFilterProxyfilter-class>

       

        <init-param>

            <param-name>targetFilterLifecycleparam-name>

            <param-value>trueparam-value>

        init-param>

       

        <init-param>

            <param-name>targetBeanNameparam-name>

            <param-value>shiroFilterparam-value>

        init-param>

    filter>

    <filter-mapping>

        <filter-name>shiroFilterfilter-name>

        <url-pattern>/*url-pattern>

    filter-mapping>

 

 

 

applicationContext-shiro.xml

  

   <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">

      <property name="securityManager" ref="securityManager" />

     

      <property name="loginUrl" value="/login.do" />

     

      <property name="successUrl" value="/index.do"/>

     

      <property name="unauthorizedUrl" value="/refuse.do" />

     

      <property name="filterChainDefinitions">

         <value>

           

            /login.do=authc

            /logout=logout

        

            /** = anon

           

           

         value>

      property>

   bean>

  

   <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">

      <property name="realm" ref="customRealm">property>

      <property name="sessionManager" ref="sessionManager">property> 

   bean>

   <bean id="customRealm" class="cn.sxt.shiro.realm.CustomRealm">

     

      <property name="credentialsMatcher" ref="credentialsMatcher">property>

   bean>

 

securityManager:这个属性是必须的。

loginUrl:没有登录认证的用户请求将跳转到此地址进行认证,不是必须的属性,不输入地址的话会自动寻找项目web项目的根目录下的”/login.jsp”页面。

unauthorizedUrl:没有权限默认跳转的页面。

自定义realm

此realm先不从数据库查询权限数据,当前需要先将shiro整合完成,在上边章节定义的realm基础上修改。

 

public class CustomRealm extends AuthorizingRealm{

   @Autowired

   private UserService userService;

   @Autowired

   private PermissionService permissionService;

   @Override

   public String getName() {

      return "CustomRealm";

   }

   /**

    * 完成认证

    * */

   protected AuthenticationInfo doGetAuthenticationInfo(

         AuthenticationToken token) throws AuthenticationException {

      //完成认证信息验证

      String userName = token.getPrincipal().toString();

      User currentUser=null;

      try {

         currentUser = userService.login(userName);

         //设置菜单

         currentUser.setMenus(permissionService.findMenuByUser(currentUser.getId()));

         //设置权限

         currentUser.setPermissions(permissionService.findPermissionByUser(currentUser.getId()));

      } catch (Exception e) {

         e.printStackTrace();

      }

      if(currentUser==null){

         return null;

      }

      SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(currentUser, currentUser.getPwd(),

            ByteSource.Util.bytes(currentUser.getSalt()),getName());

      return info;

   }

 

   /**

    * 完成授权

    * */

   protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

      //获取用户名

      User currentUser = (User)principalCollection.getPrimaryPrincipal();

     

      SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

      Set permission = new HashSet();

      for(Permission p:currentUser.getPermissions()){

         permission.add(p.getPercode());

      }

      info.addStringPermissions(permission);

      return info;

   }

}

 

登录

// 用户登陆提交

    @RequestMapping("/login")

    public String loginsubmit(Model model, HttpServletRequest request)

            throws Exception {

 

        // shiro在认证过程中出现错误后将异常类路径通过request返回

        String exceptionClassName = (String) request

                .getAttribute("shiroLoginFailure");

        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();//最终在异常处理器生成未知错误

            }

        }

        return"login";      

    }

 

首页

 

    由于session由shiro管理,需要修改首页的controller方法,将session中的数据通过model传到页面。

 

//系统首页

    @RequestMapping("/index")

   public ModelAndView index(ModelMap map){

      Subject subject = SecurityUtils.getSubject();

      User currentUser = (User)subject.getPrincipal();

      map.addAttribute("currentUser", currentUser);

      return new ModelAndView("index");

   }

 

 

退出

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

/logout.action = logout

无权限refuse.jsp

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

第四节课备课参考

核心脉络

在上一节的内容中,将shiro整合进了集成项目。实现了登录,接下来实现在集成项目中认证和授权的实现。

重点:

1. 在集成项目中实现权限控制

 

难点:

1. 在集成项目中实现权限控制

认证

添加凭证匹配器

添加凭证匹配器实现md5加密校验。

修改applicationContext-shiro.xml:

   <bean id="customRealm" class="cn.sxt.shiro.realm.CustomRealm">

     

      <property name="credentialsMatcher" ref="credentialsMatcher">property>

   bean>

  

   <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">

      <property name="hashAlgorithmName" value="md5">property>

      <property name="hashIterations" value="1">property>

   bean>

 

    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/> 

修改realm认证方法

修改realm代码从数据库中查询用户身份信息,将sysService注入realm。

public class CustomRealm extends AuthorizingRealm{

   @Autowired

   private UserService userService;

   @Autowired

   private PermissionService permissionService;

   @Override

   public String getName() {

      return "CustomRealm";

   }

   /**

    * 完成认证

    * */

   protected AuthenticationInfo doGetAuthenticationInfo(

         AuthenticationToken token) throws AuthenticationException {

      //完成认证信息验证

      String userName = token.getPrincipal().toString();

      User currentUser=null;

      try {

         currentUser = userService.login(userName);

         //设置菜单

         currentUser.setMenus(permissionService.findMenuByUser(currentUser.getId()));

         //设置权限

         currentUser.setPermissions(permissionService.findPermissionByUser(currentUser.getId()));

      } catch (Exception e) {

         e.printStackTrace();

      }

      if(currentUser==null){

         return null;

      }

      SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(currentUser, currentUser.getPwd(),

            ByteSource.Util.bytes(currentUser.getSalt()),getName());

      return info;

   }

 

}

 

授权

修改realm授权方法

修改realm代码从数据库中查询权限信息,将sysService注入realm。

public class CustomRealm extends AuthorizingRealm{

   @Autowired

   private UserService userService;

   @Autowired

   private PermissionService permissionService;

   @Override

   public String getName() {

      return "CustomRealm";

   }

      /**

    * 完成授权

    * */

   protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

      //获取用户名

      User currentUser = (User)principalCollection.getPrimaryPrincipal();

     

      SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

      Set permission = new HashSet();

      for(Permission p:currentUser.getPermissions()){

         permission.add(p.getPercode());

      }

      info.addStringPermissions(permission);

      return info;

   }

 

  

}

 

 

对controller开启AOP

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

    <aop:config proxy-target-class="true">aop:config>

   

    <bean

        class="

org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">

        <property name="securityManager" ref="securityManager" />

    bean>

 

权限注解控制

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

// 查询商品列表

    @RequestMapping("/queryItem")

    @RequiresPermissions("item:query")

    public ModelAndView queryItem() throws Exception {

 

上边代码@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

 

// 商品修改提交

    @RequestMapping("/editItemSubmit")

    @RequiresPermissions("item:update")

    public String editItemSubmit(@ModelAttribute("item") Items items,BindingResult result,

            MultipartFile pictureFile,Model model,HttpServletRequest request)

            throws Exception

 

 

jsp标签控制

标签介绍

Jsp页面添加:

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

 

标签名称

标签条件(均是显示标签内容)

登录之后

不在登录状态时

用户在没有RememberMe时

用户在RememberMe时

在有abc或者123角色时

拥有角色abc

没有角色abc

拥有权限资源abc

没有abc权限资源

显示用户身份名称

      显示用户身份中的属性值

jsp页面添加标签

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

<shiro:hasPermission name="item:update">

    <a href="${pageContext.request.contextPath }/item/editItem.action?id=${item.id}">修改a>

    shiro:hasPermission>

 

第五节课备课参考

核心脉络

Shiro除了提供认证授权外还提供验证码,记住我等其他常见功能。

验证码

自定义FormAuthenticationFilter

需要在验证账号和名称之前校验验证码。

public class MyFormAuthenticationFilter extends FormAuthenticationFilter {

    protected boolean onAccessDenied(ServletRequest request,

            ServletResponse response, Object mappedValue) throws Exception {

 

        // 校验验证码

        // session获取正确的验证码

        HttpSession session = ((HttpServletRequest)request).getSession();

        //页面输入的验证码

        String randomcode = request.getParameter("randomcode");

        //session中取出验证码

        String validateCode = (String) session.getAttribute("validateCode");

        if (randomcode!=null && validateCode!=null) {

            if (!randomcode.equals(validateCode)) {

                // randomCodeError表示验证码错误

                request.setAttribute("shiroLoginFailure", "randomCodeError");

                //拒绝访问,不再校验账号和密码

                return true;

            }

        }

        return super.onAccessDenied(request, response, mappedValue);

    }

}

 

 

FormAuthenticationFilter配置

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

 

n  在shiroFilter中添加filters:

 

<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">

        <property name="filters">

            <map>

               

                <entry key="authc" value-ref="formAuthenticationFilter" />

            map>

        property>

 

n  formAuthenticationFilter定义

    <bean id="formAuthenticationFilter"

    class="org.apache.shiro.web.filter.authc.MyFormAuthenticationFilter ">

       

        <property name="usernameParam" value="username" />

       

        <property name="passwordParam" value="password" />

 bean>

 

登陆页面

添加验证码:

<TR>

                            <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>

                        TR>

 

配置validatecode.jsp匿名访问

修改applicationContext-shiro.xml:

 

 

记住我

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

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

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

 

 

 

配置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"/>

       

        "rememberMeManager" ref="rememberMeManager"/>

    bean>

    <bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">

        <property name="cookie" ref="rememberMeCookie" />

    bean>

   

    <bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie">

        <constructor-arg value="rememberMe" />

       

        <property name="maxAge" value="2592000" />

    bean>

FormAuthenticationFilter配置

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

<bean id="formAuthenticationFilter"

        class="cn.itcast.ssm.shiro.MyFormAuthenticationFilter">

       

        <property name="usernameParam" value="usercode" />

       

        <property name="passwordParam" value="password" />

        "rememberMeParam" value="rememberMe"/>

    bean>

登陆页面

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

<TR>

                            <TD>TD>

                            <TD>

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

                            TD>

                        TR>

 

你可能感兴趣的:(框架-shiro)