1、整合shiro
1.1、创建spring boot项目
1.2、引入依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-web-starter</artifactId>
<version>1.9.0</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
1.3、添加配置文件
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
mapper-locations: classpath:mapper/*.xml
spring:
datasource:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/shirodb?characterEncoding=utf-8&useSSL=false
username: root
password: zzybzb
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
shiro:
loginUrl: /myController/login
1.4、启动类添加扫描包注解

2、登录认证实现
2.1、库表
2.1.1、建表
CREATE DATABASE IF NOT EXISTS `shirodb` CHARACTER SET utf8mb4;
USE `shirodb`;
CREATE TABLE `user` (
`id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '编号',
`name` VARCHAR(30) DEFAULT NULL COMMENT '用户名',
`pwd` VARCHAR(50) DEFAULT NULL COMMENT '密码',
`rid` BIGINT(20) DEFAULT NULL COMMENT '角色编号',
PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='用户表';
2.1.2、密码加密,添加几条数据
public class ShiroMD5 {
public static void main(String[] args) {
String password = "123456";
Md5Hash md53 = new Md5Hash(password,"salt",3);
System.out.println("md5带盐的3次加密:"+md53.toHex());
}
}

2.2、创建实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User implements Serializable {
private Integer id;
private String name;
private String pwd;
private Integer rid;
}
2.3、创建 mapper
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
2.4、创建 service
public interface UserService {
User getUserInfoByName(String name);
}
@Service
public class UserServiceImpl implements UserService {
private UserMapper userMapper;
@Autowired
public UserServiceImpl(UserMapper userMapper) {
this.userMapper = userMapper;
}
@Override
public User getUserInfoByName(String name) {
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("name",name);
User user = userMapper.selectOne(wrapper);
return user;
}
}
2.5、自定义realm
@Component
public class MyRealm extends AuthorizingRealm {
private UserService userService;
@Autowired
public MyRealm(UserService userService){
this.userService = userService;
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
String username = authenticationToken.getPrincipal().toString();
User user = userService.getUserInfoByName(username);
if (user != null){
AuthenticationInfo info = new SimpleAuthenticationInfo(
authenticationToken.getPrincipal(),
user.getPwd(),
ByteSource.Util.bytes("salt"),
authenticationToken.getPrincipal().toString()
);
return info;
}
return null;
}
}
2.6、配置类
@Configuration
public class ShiroConfig {
private MyRealm myRealm;
@Autowired
public ShiroConfig(MyRealm myRealm){
this.myRealm = myRealm;
}
@Bean
public DefaultWebSecurityManager defaultWebSecurityManager(){
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
matcher.setHashAlgorithmName("MD5");
matcher.setHashIterations(3);
myRealm.setCredentialsMatcher(matcher);
defaultWebSecurityManager.setRealm(myRealm);
return defaultWebSecurityManager;
}
@Bean
public DefaultShiroFilterChainDefinition shiroFilterChainDefinition(){
DefaultShiroFilterChainDefinition definition = new DefaultShiroFilterChainDefinition();
definition.addPathDefinition("/my/userLogin","anon");
definition.addPathDefinition("/my/login","anon");
definition.addPathDefinition("/logout","logout");
definition.addPathDefinition("/**","authc");
definition.addPathDefinition("/**","user");
return definition;
}
}
2.7、controller
@Controller
@RequestMapping("/my")
public class MyController {
@RequestMapping("/userLogin")
@ResponseBody
public String login(String username,String password){
Subject subject = SecurityUtils.getSubject();
AuthenticationToken token = new UsernamePasswordToken(username,password);
try {
subject.login(token);
return "登录成功";
} catch (AuthenticationException e) {
e.printStackTrace();
return "登录失败";
}
}
}
2.8、访问,测试
 
2.9、实现前端页面
2.9.1、Thymeleaf依赖
dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
2.9.2、login 页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>Shiro登录认证</h1>
<br>
<form action="/my/userLogin">
<div>用户名:<input type="text" name="username" value=""></div>
<div>密码:<input type="password" name="password" value=""></div>
<div><input type="submit" value="登录"></div>
</form>
</body>
</html>
2.9.3、添加 index 页面
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
xmlns:shiro="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>Shiro登录认证后主页面</h1>
<br>
登录用户为:<span th:text="${session.user}"></span>
</body>
2.9.4、添加 controller 方法,改造认证方法
@RequestMapping("/login")
public String login(){
return "login";
}

2.9.5、修改配置文件

2.9.6、修改配置类

2.9.7、访问,测试
 
3、多个 realm 的认证策略设置
3.1、多个realm实现原理
当应用程序配置多个 Realm 时,例如:用户名密码校验、手机号验证码校验等等。 Shiro 的 ModularRealmAuthenticator 会使用内部的 AuthenticationStrategy 组件判断认证是成功还是失败。 AuthenticationStrategy 是一个无状态的组件,它在身份验证尝试中被询问 4 次(这4 次交互所需的任何必要的状态将被作为方法参数):
- 在所有 Realm 被调用之前
- 在调用 Realm 的 getAuthenticationInfo 方法之前
- 在调用 Realm 的 getAuthenticationInfo 方法之后
- 在所有 Realm 被调用之后
认证策略的另外一项工作就是聚合所有 Realm 的结果信息封装至一个 AuthenticationInfo 实例中,并将此信息返回,以此作为 Subject 的身份信息。
Shiro 中定义了 3 种认证策略的实现:
-
AtLeastOneSuccessfulStrategy 只要有一个(或更多)的 Realm 验证成功,那么认证将视为成功。 -
FirstSuccessfulStrategy 第一个 Realm 验证成功,整体认证将视为成功,且后续 Realm 将被忽略。 -
AllSuccessfulStrategy 所有 Realm 成功,认证才视为成功。
ModularRealmAuthenticator 内置的认证策略默认实现是 AtLeastOneSuccessfulStrategy 方式。可以通过配置修改策略。
3.2、多个realm代码实现
@Bean
public DefaultWebSecurityManager defaultWebSecurityManager(){
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
ModularRealmAuthenticator modularRealmAuthenticator = new ModularRealmAuthenticator();
modularRealmAuthenticator.setAuthenticationStrategy(new AllSuccessfulStrategy());
defaultWebSecurityManager.setAuthenticator(modularRealmAuthenticator);
List<Realm> list = new ArrayList<>();
list.add(myRealm);
list.add(myRealm2);
defaultWebSecurityManager.setRealms(list);
return defaultWebSecurityManager;
}
4、remember me 功能
Shiro 提供了记住我(RememberMe)的功能,比如访问一些网站时,关闭了浏览器,下次再打开时还是能记住你是谁, 下次访问时无需再登录即可访问。
4.1、基本流程
- 首先在登录页面选中 RememberMe 然后登录成功;如果是浏览器登录,一般会 把 RememberMe 的 Cookie 写到客户端并保存下来。
- 关闭浏览器再重新打开;会发现浏览器还是记住你的。
- 访问一般的网页服务器端,仍然知道你是谁,且能正常访问。
- 但是,如果我们访问电商平台时,如果要查看我的订单或进行支付时,此时还是需要再进行身份认证的,以确保当前用户还是你。
4.2、代码实现
4.2.1、修改配置类
public SimpleCookie rememberMeCookie(){
SimpleCookie cookie = new SimpleCookie("rememberMe");
cookie.setPath("/");
cookie.setHttpOnly(true);
cookie.setMaxAge(30*24*60*60);
return cookie;
}
public CookieRememberMeManager rememberMeManager(){
CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
cookieRememberMeManager.setCookie(rememberMeCookie());
cookieRememberMeManager.setCipherKey("1234567890987654".getBytes());
return cookieRememberMeManager;
}
defaultWebSecurityManager.setRememberMeManager(rememberMeManager());
 
4.2.2、添加,修改 controller
添加
@GetMapping("userLoginRm")
public String userLogin(HttpSession session) {
session.setAttribute("user","rememberMe");
return "index";
}
修改 
4.2.3、修改登录页面
<div>记住用户:<input type="checkbox" name="rememberMe" value="true"></div>

4.3、访问测试
4.3.1、未勾选
- 登录


- 访问userLoginRm
 - 关掉浏览器后打开,重新访问

4.3.2、勾选“记住我”
 
- 关掉浏览器再访问

5、退出
用户登录后,配套的有登出操作。直接通过Shiro过滤器即可实现登出。
5.1、index页面
<a href="/logout">登出</a>
5.2、修改配置类
definition.addPathDefinition("/logout","logout");

5.3、测试
 
6、授权、角色认证
6.1、授权
用户登录后,需要验证是否具有指定角色指定权限。Shiro也提供了方便的工具进行判断。这个工具就是Realm的doGetAuthorizationInfo方法进行判断。
触发权限判断的有两种方式
- 在页面中通过shiro:****属性判断
- 在接口服务中通过注解@Requires****进行判断
6.2、后端接口服务注解
通过给接口服务方法添加注解可以实现权限校验,可以加在控制器方法上,也可以加在业务方法上,一般加在控制器方法上。常用注解如下:
-
@RequiresAuthentication 验证用户是否登录,等同于方法subject.isAuthenticated() -
@RequiresUser 验证用户是否被记忆: 登录认证成功subject.isAuthenticated()为true。 登录后被记忆subject.isRemembered()为true。 -
@RequiresGuest 验证是否是一个guest的请求,是否是游客的请求。 此时subject.getPrincipal()为null。 -
@RequiresRoles 验证subject是否有相应角色,有角色访问方法,没有则会抛出异常AuthorizationException。 例如:
@RequiresRoles(“aRoleName”)
void someMethod();
- @RequiresPermissions
验证subject是否有相应权限,有权限访问方法,没有则会抛出异常AuthorizationException。 例如:
@RequiresPermissions ("file:read","wite:aFile.txt")
void someMethod();
6.3、授权验证-没有角色无法访问
6.3.1、controller代码
@RequiresRoles("admin")
@GetMapping("userLoginRoles")
@ResponseBody
public String userLoginRoles(){
System.out.println("登录认证验证角色");
return "验证角色成功";
}
6.3.2、index页面
<a shiro:hasRole="admin" href="/my/userLoginRoles">测试授权-角色验证</a>
6.3.3、修改MyRealm类的doGetAuthorizationInfo方法

6.3.4、测试,没有admin角色,会报错
  
6.4、授权验证-获取角色进行验证
6.4.1、修改 MyRealm 方法
自定义授权方法:获取当前登录用户权限信息,返回给 Shiro 用来进行授权对比
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addRole("admin");

 
6.4.2、角色表,用户-角色中间表
CREATE TABLE `role` (
`id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '编号',
`name` VARCHAR(30) DEFAULT NULL COMMENT '角色名',
`desc` VARCHAR(50) DEFAULT NULL COMMENT '描述',
`realname` VARCHAR(20) DEFAULT NULL COMMENT '角色显示名',
PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='角色表';
CREATE TABLE `role_user` (
`id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '编号',
`uid` BIGINT(20) DEFAULT NULL COMMENT '用户 id',
`rid` BIGINT(20) DEFAULT NULL COMMENT '角色 id',
PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='角色用户映射
表';
自定义数据–角色表 
自定义数据–用户角色中间表 
6.4.3、查询 sql
根据用户名查询对应角色信息
SELECT NAME FROM role WHERE id IN (SELECT rid FROM role_user WHERE
uid=(SELECT id FROM USER WHERE NAME='zhangsan'));

6.4.4、mapper 方法
@Select("SELECT NAME FROM role WHERE id IN (SELECT rid FROM role_user WHERE uid=(SELECT id FROM USER WHERE NAME=#{principal}))")
List<String> getUserRoleInfoMapper(@Param("principal")String principal );
6.4.5、service 方法
@Override
public List<String> getUserRoleInfo(String principal) {
return userMapper.getUserRoleInfoMapper(principal);
}
6.4.6、MyRealm 方法改造
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("进入自定义授权方法");
String principal = principalCollection.getPrimaryPrincipal().toString();
List<String> roles = userService.getUserRoleInfo(principal);
System.out.println("当前用户角色信息 = " + roles);
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addRoles(roles);
return info;
}
6.4.7、启动测试
 
6.5、授权验证-获取权限进行验证
6.5.1、权限表(菜单表),角色权限中间表
CREATE TABLE `permissions` (
`id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '编号',
`name` VARCHAR(30) DEFAULT NULL COMMENT '权限名',
`info` VARCHAR(30) DEFAULT NULL COMMENT '权限信息',
`desc` VARCHAR(50) DEFAULT NULL COMMENT '描述',
PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='权限表';
CREATE TABLE `role_ps` (
`id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '编号',
`rid` BIGINT(20) DEFAULT NULL COMMENT '角色 id',
`pid` BIGINT(20) DEFAULT NULL COMMENT '权限 id',
PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='角色权限映射表';
自定义数据–权限表 
自定义数据–角色权限表

6.5.2、查询 sql
根据角色名查询对应权限信息
SELECT info FROM permissions WHERE id IN (SELECT pid FROM role_ps WHERE rid
IN (SELECT id FROM role WHERE NAME IN('admin','user')));
6.5.3、mapper 方法
@Select({
"<script>",
"select info FROM permissions WHERE id IN ",
"(SELECT pid FROM role_ps WHERE rid IN (",
"SELECT id FROM role WHERE NAME IN ",
"<foreach collection='roles' item='name' open='(' separator=',' close=')'>",
"#{name}",
"</foreach>",
"))",
"</script>"
})
List<String> getUserPermissionInfoMapper(@Param("roles")List<String> roles);
6.5.4、service代码
@Override
public List<String> getUserPermissionInfo(List<String> roles) {
return userMapper.getUserPermissionInfoMapper(roles);
}
6.5.5、realm代码

6.5.6、controller 方法
@RequiresPermissions("user:del")
@GetMapping("userPermissions")
@ResponseBody
public String userLoginPermissions(){
System.out.println("登录认证验证权限");
return "验证权限成功";
}
6.5.7、index页面
<a shiro:hasPermission="user:delete" href="/my/userPermissions">测试授权-权限验证</a>
6.5.8、测试

 
6.6、授权验证-异常处理
创建认证异常处理类,使用@ControllerAdvice 加@ExceptionHandler 实现特殊异常处理。
package com.bz.shiro.controller;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
@ControllerAdvice
public class PermissionsException {
@ResponseBody
@ExceptionHandler(UnauthorizedException.class)
public String unauthorizedException(Exception e){
return "无权限";
}
@ResponseBody
@ExceptionHandler(AuthorizationException.class)
public String authorizationException(Exception e){
return "权限认证失败";
}
}
lisi账号登录  
6.7、前页面授权验证
6.7.1、引入依赖
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
6.7.2、配置类添加新配置
@Bean
public ShiroDialect shiroDialect(){
return new ShiroDialect();
}
6.7.3、Thymeleaf 中常用的 shiro:属性
- guest 标签
用户没有身份验证时显示相应信息,即游客访问信息。
<shiro:guest></shiro:guest>
- user 标签
用户已经身份验证/记住我登录后显示相应的信息。
<shiro:user></shiro:user>
- authenticated 标签
用户已经身份验证通过,即 Subject.login 登录成功,不是记住我登录的。
<shiro:authenticated></shiro:authenticated>
- notAuthenticated 标签
用户已经身份验证通过,即没有调用 Subject.login 进行登录,包括记住我自动登录的也属于未进行身份验证。
<shiro:notAuthenticated></shiro:notAuthenticated>
- principal 标签
相当于((User)Subject.getPrincipals()).getUsername()。
<shiro: principal/><shiro:principal property="username"/>
- lacksPermission 标签
如果当前 Subject 没有权限将显示 body 体内容。
<shiro:lacksPermission name="org:create"></shiro:lacksPermission>
- hasRole 标签
如果当前 Subject 有角色将显示 body 体内容。
<shiro:hasRole name="admin"></shiro:hasRole>
- hasAnyRoles 标签
如果当前 Subject 有任意一个角色(或的关系)将显示 body 体内容。
<shiro:hasAnyRoles name="admin,user"></shiro:hasAnyRoles>
- lacksRole 标签
如果当前 Subject 没有角色将显示 body 体内容。
<shiro:lacksRole name="abc"></shiro:lacksRole>
- hasPermission 标签
如果当前 Subject 有权限将显示 body 体内容
<shiro:hasPermission name="user:create"></shiro:hasPermission>
6.7.4、修改index页面
 
 
- lisi登录
 
7、实现缓存
7.1、缓存工具EhCache
EhCache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存,Java EE和轻量级容器。可以和大部分Java项目无缝整合,例如:Hibernate中的缓存就是基于EhCache实现的。
EhCache支持内存和磁盘存储,默认存储在内存中,如内存不够时把缓存数据同步到磁盘中。EhCache支持基于Filter的Cache实现,也支持Gzip压缩算法。
EhCache直接在JVM虚拟机中缓存,速度快,效率高; EhCache缺点是缓存共享麻烦,集群分布式应用使用不方便。
7.2、新建项目
7.2.1、引入依赖
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.6.11</version>
<type>pom</type>
</dependency>
7.2.2、添加配置文件 ehcache.xml
<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
<diskStore path="java.io.tmpdir/ehcache"/>
<defaultCache
maxEntriesLocalHeap="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
maxEntriesLocalDisk="10000000"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
<persistence strategy="localTempSwap"/>
</defaultCache>
<cache name="HelloWorldCache"
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="5"
timeToLiveSeconds="5"
overflowToDisk="false"
memoryStoreEvictionPolicy="LRU"/>
</ehcache>
7.2.3、测试类
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;
import java.io.InputStream;
public class TestEH {
public static void main(String[] args) {
InputStream input =
TestEH.class.getClassLoader().getResourceAsStream("ehcache.xml");
CacheManager cacheManager = new CacheManager(input);
Cache cache = cacheManager.getCache("HelloWorldCache");
Element element = new Element("name","zhang3");
cache.put(element);
Element element1 = cache.get("name");
System.out.println("缓存中数据 = " + element1.getObjectValue());
}
}
7.2.4、启动

7.3、Shiro整合EhCache
Shiro官方提供了shiro-ehcache,实现了整合EhCache作为Shiro的缓存工具。可以缓存认证执行的Realm方法,减少对数据库的访问,提高认证效率。
7.3.1、引入依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.4.2</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
7.3.2、在 resources 下添加配置文件 ehcache/ehcache-shiro.xml
<?xml version="1.0" encoding="UTF-8"?>
<ehcache name="ehcache" updateCheck="false">
<diskStore path="java.io.tmpdir"/>
<defaultCache
maxEntriesLocalHeap="1000"
eternal="false"
timeToIdleSeconds="3600"
timeToLiveSeconds="3600"
overflowToDisk="false">
</defaultCache>
<cache name="loginRolePsCache"
maxEntriesLocalHeap="2000"
eternal="false"
timeToIdleSeconds="600"
timeToLiveSeconds="0"
overflowToDisk="false"
statistics="true"/>
</ehcache>
7.3.3、修改配置类 ShiroConfig
public EhCacheManager getEhCacheManager(){
EhCacheManager ehCacheManager = new EhCacheManager();
InputStream is =null;
try {
is = ResourceUtils.getInputStreamForPath("classpath:ehcache/ehcache-shiro.xml");
} catch (IOException e) {
e.printStackTrace();
}
CacheManager cacheManager = new CacheManager(is);
ehCacheManager.setCacheManager(cacheManager);
return ehCacheManager;
}
 
7.3.4、测试
- 第一次登录可以看到查询角色、权限信息

  
8、会话管理
8.1、SessionManager
会话管理器,负责创建和管理用户的会话(Session)生命周期,它能够在任何环境中在本地管理用户会话,即使没有Web/Servlet/EJB容器,也一样可以保存会话。默认情况下,Shiro会检测当前环境中现有的会话机制(比如Servlet容器)进行适配,如果没有(比如独立应用程序或者非Web环境),它将会使用内置的企业会话管理器来提供相应的会话管理服务,其中还涉及一个名为SessionDAO的对象。SessionDAO负责Session的持久化操作(CRUD),允许Session数据写入到后端持久化数据库。
8.2、会话管理实现
SessionManager由SecurityManager管理。 Shiro提供了三种实现 
- DefaultSessionManager:用于JavaSE环境
- ServletContainerSessionManager:用于web环境,直接使用Servlet容器的会话
- DefaultWebSessionManager:用于web环境,自己维护会话(不使用Servlet容器的 会话管理)。
8.3、获得session方式
- 实现
Session session = SecurityUtils.getSubject().getSession();
session.setAttribute(“key”,”value”)
-
说明 Controller 中的 request,在 shiro 过滤器中的 doFilerInternal 方法,被包装成ShiroHttpServletRequest。 SecurityManager 和 SessionManager 会话管理器决定 session 来源于 ServletRequest还是由 Shiro 管理的会话。 无论是通过 request.getSession 或 subject.getSession 获取到 session,操作session,两者都是等价的。
结束!!!
人应尊敬他自己,并应自视能配得上最高尚的东西。——黑格尔
|