1:创建springboot项目路径如下
2:pom.xml的配置
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>springbootshiro</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springbootshiro</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring.shiro.version>1.6.0</spring.shiro.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- shiro -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>${spring.shiro.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--页面模板依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!--热部署依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3:创建三个bean,Permissions,Role,User
@Data
@AllArgsConstructor
public class Permissions {
private String id;
private String permissionsName;
}
@Data
@AllArgsConstructor
public class Role {
private String id;
private String roleName;
/**
* 角色对应权限集合
*/
private Set<Permissions> permissions;
}
@Data
@AllArgsConstructor
public class User {
private String id;
private String userName;
private String password;
private String mobile;
private String email;
/**
* 用户对应的角色集合
*/
private Set<Role> roles;
}
4:创建controller
@RestController
@Slf4j
public class LoginController {
@GetMapping("/login")
public String login(User user) {
if (!StringUtils.hasLength(user.getUserName()) || !StringUtils.hasLength(user.getPassword())) {
return "请输入用户名和密码!";
}
//用户认证信息
Subject subject = SecurityUtils.getSubject();
if(!subject.isAuthenticated() && !subject.isRemembered()) {
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(
user.getUserName(),
user.getPassword()
);
usernamePasswordToken.setRememberMe(true);
try {
//进行验证,这里可以捕获异常,然后返回对应信息
subject.login(usernamePasswordToken);
} catch (UnknownAccountException e) {
log.error("用户名不存在!", e);
return "用户名不存在!";
} catch (AuthenticationException e) {
log.error("账号或密码错误!", e);
return "账号或密码错误!";
} catch (AuthorizationException e) {
log.error("没有权限!", e);
return "没有权限";
}
}
return "login success";
}
@RequiresRoles("admin")
@GetMapping("/admin")
public String admin() {
System.out.println("====admin========");
return "admin success!";
}
@RequiresPermissions("add")
@GetMapping("/add")
public String add() {
System.out.println("====add========");
return "add success!";
}
@GetMapping("/tologout")
@RequiresGuest
public String logout() {
System.out.println("====logout========");
Subject subject = SecurityUtils.getSubject();
subject.logout();
return "logout success!";
}
}
5:创建service和impl
public interface LoginService {
User getUserByName(String getMapByName);
User getUserByMobile(String getMapByMobile);
User getUserByEmail(String getMapByEmail);
}
@Service
public class LoginServiceImpl implements LoginService {
/**
* 模拟数据库查询
* @param mobile 电话号码
* @return User
*/
@SneakyThrows
@Override
public User getUserByMobile(String mobile) {
User user=null;
List<User> map=getMap();
List<User> users=map.stream().filter(usera->usera.getMobile().equals(mobile)).collect(Collectors.toList());
if (null !=users && users.size()>0) {
user=users.get(0);
}
return user;
}
/**
* 模拟数据库查询
* @param email 邮箱
* @return User
*/
@SneakyThrows
@Override
public User getUserByEmail(String email) {
User user=null;
List<User> map=getMap();
List<User> users=map.stream().filter(usera->usera.getEmail().equals(email)).collect(Collectors.toList());
if (null !=users && users.size()>0) {
user=users.get(0);
}
return user;
}
/**
* 模拟数据库查询
* @param userName 用户名
* @return User
*/
@Override
public User getUserByName(String userName) {
User user=null;
List<User> map=getMap();
List<User> users=map.stream().filter(usera->usera.getUserName().equals(userName)).collect(Collectors.toList());
if (null !=users && users.size()>0) {
// user=(User)BeanUtils.cloneBean(users.get(0));
user=users.get(0);
}
return user;
}
private List<User> getMap(){
Permissions permissions1 = new Permissions("1", "query");
Permissions permissions2 = new Permissions("2", "add");
Set<Permissions> permissionsSet = new HashSet<>();
permissionsSet.add(permissions1);
permissionsSet.add(permissions2);
Role role = new Role("1", "admin", permissionsSet);
Set<Role> roleSet = new HashSet<>();
roleSet.add(role);
User user = new User("1", "lisi", "42e6bf42ff7204ea6635698494c4111e","13800000000","88888888", roleSet);
List list=new ArrayList<>();
list.add(user);
Set<Permissions> permissionsSet1 = new HashSet<>();
permissionsSet1.add(permissions1);
Role role1 = new Role("2", "user", permissionsSet1);
Set<Role> roleSet1 = new HashSet<>();
roleSet1.add(role1);
User user1 = new User("2", "zhangsan", "42e6bf42ff7204ea6635698494c4111e","13900000000","99999999", roleSet1);
list.add(user1);
return list;
}
}
6:创建三个shiro的realm
1:用户reaml
public class MyRealm extends AuthorizingRealm {
@Autowired
private LoginService loginService;
/**
* @MethodName doGetAuthorizationInfo
* @Description 权限配置类
* @Param [principalCollection]
* @Return AuthorizationInfo
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//获取登录用户名
String name = (String) principalCollection.getPrimaryPrincipal();
//查询用户名称
User user = loginService.getUserByName(name);
//添加角色和权限
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
for (Role role : user.getRoles()) {
//添加角色
simpleAuthorizationInfo.addRole(role.getRoleName());
//添加权限
for (Permissions permissions : role.getPermissions()) {
simpleAuthorizationInfo.addStringPermission(permissions.getPermissionsName());
}
}
return simpleAuthorizationInfo;
}
/**
* @MethodName doGetAuthenticationInfo
* @Description 认证配置类
* @Param [authenticationToken]
* @Return AuthenticationInfo
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
if (StringUtils.isEmpty(authenticationToken.getPrincipal())) {
return null;
}
//获取用户信息
String name = authenticationToken.getPrincipal().toString();
User user = loginService.getUserByName(name);
if (user == null) {
//这里返回后会报出对应异常
return null;
} else {
//这里验证authenticationToken和simpleAuthenticationInfo的信息
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(name, user.getPassword().toString(),new SimpleByteSource("salt") ,getName());
return simpleAuthenticationInfo;
}
}
}
2:邮箱realm
public class EmailRealm extends AuthenticatingRealm {
@Autowired
private LoginService loginService;
/**
* @MethodName doGetAuthenticationInfo
* @Description 认证配置类
* @Param [authenticationToken]
* @Return AuthenticationInfo
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
if (StringUtils.isEmpty(authenticationToken.getPrincipal())) {
return null;
}
//获取用户信息
String email = authenticationToken.getPrincipal().toString();
User user = loginService.getUserByEmail(email);
if (user == null) {
//这里返回后会报出对应异常
return null;
} else {
//这里验证authenticationToken和simpleAuthenticationInfo的信息
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(email, user.getPassword().toString(),new SimpleByteSource("salt"), getName());
return simpleAuthenticationInfo;
}
}
}
3:电话realm
public class MobileRealm extends AuthenticatingRealm {
@Autowired
private LoginService loginService;
/**
* @MethodName doGetAuthenticationInfo
* @Description 认证配置类
* @Param [authenticationToken]
* @Return AuthenticationInfo
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
if (StringUtils.isEmpty(authenticationToken.getPrincipal())) {
return null;
}
//获取用户信息
String mobile = authenticationToken.getPrincipal().toString();
User user = loginService.getUserByMobile(mobile);
if (user == null) {
//这里返回后会报出对应异常
return null;
} else {
//这里验证authenticationToken和simpleAuthenticationInfo的信息
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(mobile, user.getPassword().toString(),new SimpleByteSource("salt"), getName());
return simpleAuthenticationInfo;
}
}
}
7:主要的配置文件config,shiro必须会三步骤,三板斧设置
1:Realms 代表资源(Realms)
2:SecurityManager 流程控制(DefultSecurityManager)
3:ShiroFilterFactoruBean 请求过滤器(ShiroFilterFactoruBean)
@Configuration
public class ShiroConfig {
/**
* 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions)
* LifecycleBeanPostProcessor 是管理shiro生命周期的,不直接跟权限注解关联。所以加上DefaultAdvisorAutoProxyCreator 这个bean就可以了
* 配置以下两个bean(DefaultAdvisorAutoProxyCreator和AuthorizationAttributeSourceAdvisor)即可实现此功能
*
* @return
*/
@Bean
//LifecycleBeanPostProcessor 是管理shiro生命周期的
//这个方法不加也可以 但是网上别的博客都说需要加
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
@Bean
public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
advisorAutoProxyCreator.setProxyTargetClass(true);
return advisorAutoProxyCreator;
}
//AuthorizationAttributeSourceAdvisor 的作用是匹配所有类 匹配所有加认证注解的方法
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
//将自己的验证方式加入容器
@Bean
public MyRealm myShiroRealm() {
MyRealm myRealm = new MyRealm();
return myRealm;
}
@Bean
public MobileRealm mobileRealm() {
MobileRealm mobileRealm = new MobileRealm();
return mobileRealm;
}
@Bean
public EmailRealm emailRealm() {
EmailRealm emailRealm = new EmailRealm();
return emailRealm;
}
//权限管理,配置主要是Realm的管理认证sets
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//密码加密
HashedCredentialsMatcher matcher=new HashedCredentialsMatcher();
matcher.setHashAlgorithmName("MD5");
matcher.setHashIterations(6);
myShiroRealm().setCredentialsMatcher(matcher);
mobileRealm().setCredentialsMatcher(matcher);
emailRealm().setCredentialsMatcher(matcher);
//securityManager.setRealms(Arrays.asList(myShiroRealm(),mobileRealm(),emailRealm()));
//多realm数据源认证
ModularRealmAuthenticator authenticator =new ModularRealmAuthenticator();
authenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy());
authenticator.setRealms(Arrays.asList(myShiroRealm(),mobileRealm(),emailRealm()));
securityManager.setAuthenticator(authenticator );
//授权的缓存设置,第一次访问需要授权,后面访问跳过doGetAuthorizationInfo授权方法
MemoryConstrainedCacheManager cacheManager=new MemoryConstrainedCacheManager();
securityManager.setCacheManager(cacheManager);
//设置记住我的时
CookieRememberMeManager rememberMeManager=new CookieRememberMeManager();
Cookie cookie=new SimpleCookie("rememberMe");
cookie.setHttpOnly(true);
cookie.setMaxAge(300);//设置时长单位为秒
rememberMeManager.setCookie(cookie);
securityManager.setRememberMeManager(rememberMeManager);
return securityManager;
}
//Filter工厂,设置对应的过滤条件和跳转条件
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
Map<String, String> map = new HashMap<>();
//anon是不需要认证的接口
map.put("/tologout", "anon");
//对所有用户认证
map.put("/**", "authc");
//登录
shiroFilterFactoryBean.setLoginUrl("/login");
//错误页面,认证不通过跳转
shiroFilterFactoryBean.setUnauthorizedUrl("/error");
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
return shiroFilterFactoryBean;
}
}
8:手动设置初次注册密码加密落库
public class Demo {
public static void main(String[] args) {
//密码加密
String password="123456";
SimpleHash simpleHash=new SimpleHash("MD5",password,new SimpleByteSource("salt"),6);
System.out.println(simpleHash);
}
}
9:创建MyExceptionHandler类
当使用shiro提供的注解,实现方级别的权限控制,
@RequestGuest //表示未登录的用户可以访问,登录用户不可以访问
@RequestAuthentication //需要完成用户登录
@RequeUser //需要完成用户登录并且完成了记住我功能
@RequestPermissions //表示有相应资源和权限
@RequestRoles //需要相应的角色
需要错误补偿机制(不然捕获不了异常):没有权限就抛出异常(自定义MyExceptionHandle在类上加上@RestControllerAdvice)
@ControllerAdvice
@Slf4j
public class MyExceptionHandler {
//@ExceptionHandler(AuthenticationException.class)
@ExceptionHandler
@ResponseBody
public String ErrorHandler(AuthorizationException e) {
log.error("没有通过权限验证!", e);
return "没有通过权限验证!";
}
}
以下是shiro知识笔记
1:shiro主要有三大功能模块
1: Subject:主体,一般指用户。
2: SecurityManager:安全管理器,管理所有Subject,可以配合内部安全组件。(类似于SpringMVC中的DispatcherServlet)
3: Realms:用于进行权限信息的验证,一般需要自己实现。
2:shiro QuickStart
//获得当前用户主体
Subjec currentUser=SecurityUtils.getSubject();
//判断是否完成认证,返回的是boolean
currentUser.isAuthenticated();
//认证 user前端传过来的账号密码
UsernamePasswordToke token=new UsernamePasswordToke(user.getName(),user.getPassword())
currentUser.login(token);//通过抛出的异常来判断用户结果
Session session=currentuser.getSession();
session.setAttribute(“curenUser”,currentuser.getPrincipal());
//获取用户名
String name=token.getPrincipal();
//授权
currentUser.hasRole(“role”);
currentUers.isPermitted(permission);
//登出
currentUser.logout();
3:认证流程
1:获取当前用户
2:根据当前用户获取数据库中得用户信息
3:当前用户和数据库中的用户进行密码匹配shiro会在后面帮我们进行密码比较(SimpleAuthenticationInfo*)
4:实现登录验证功能
1:创建自己的Realmd对象,继承AuthorizingReamls,然后实现重写父类的doGetAuthenticationInfo认证方法和doGetAuthorizationInfo授权方法
2:配置路径过滤器,anno,anth,authc,perms,role
Map<String,String> filterMap=new HashMap<>();
//key是ant路径,支持**代表多级路径,*代表单级,?代表当字符
//value配置shiro的默认过滤器,可以查看DefaultFilter类查看过滤器类型。注意:过滤器是有顺序的,谁在前面就生效谁
filterMap.put(“”,“anno”);//表示不拦截(要放在authc前面)
filterMap.put(“”,“authc”);//表示拦截,要登录才可以访问
5:修复登录认证错误的访问情况
//设置登录页(未登录访问资源的时候会跳转到登录页)
factoryBean.setLoginurl(“/tologin”)
//登录成功页,
//未经授权页
factoryBean.setUnauthorizedUrl(“/tologin”)
6:登出的两种方式
//第一种方式
@RequestMapp(“/tologgout”)
public void logout(){
Subject currentUser=SecurityUtils.getSubeject();
currentUser.loggout();
}
//第二种方式
直接配置shiro提供的过滤器,有这个请求的时候直接退出
filterMap.put(“/tologgout”,“logout”)
list中map转对象的方法,BeanUtils.cloneBean(list)
7:实现授权功能
//在MyRealm类中的doGetAuthorizationInfo授权方法操作
1:获取当前用户
2:绑定角色,资源
硬编码的方式,自行判断权限,判断是否有权限和角色
1:判断这个请求是否有这个permission权限
@RequestMapping(“/permission”)
Subject currentUser=SecurityUtils.getSubeject();
if(currentUers.isPermitted(“permission”)){
//TODO
};
2:判断这个请求是否有这个radmin角色
@RequestMapping(“/permission”)
Subject currentUser=SecurityUtils.getSubeject();
if(currentUers.hasRole(“admin”)){
//TODO
};
使用shirot提供的perms,roles过滤器,集中配置权限信息
//在路径拦截器中配置,同时配置没有权限跳转路径
filterMap.put(“/add/*”,“authc,perms[add,del],roles[admin]”);
factoryBean.setUnAuthorizedUrl(“/unauthorized”)
//错误补偿机制:没有权限就会进入ShiroFilterFactoryBean中配置的UnAuthorizedUrl
使用shiro提供的注解,实现方级别的权限控制
//错误补偿机制:没有权限就抛出异常(自定义MyExceptionHandle在类上加上@RestControllerAdvice,在 方法上加上@ExceptionHandler(AuthenticationException.class))
@RequestGuest //表示未登录的用户可以访问,登录用户不可以访问
@RequestAuthentication //需要完成用户登录
@RequeUser //需要完成用户登录并且完成了记住我功能
@RequestPermissions //表示有相应资源和权限
@RequestRoles //需要相应的角色
8: 密码加密
shiro会获取一个CredentialsMatch对象,来对密码进行比对
想要用MD5方式进行加密:
//在shiroConfig类中的SecurityManager流程控制中添加
HashedCredentialsMatcher matcher=new HashedCredentialsMatcher();
matcher.setHashAlgorithmName(“MD5”);
matcher.setHashIterations(3);
myRealm.setCredentialsMatcher(matcher);
MdCredentialsMatc已经过期,要使用HashedCredentialsMatch并设定算法名。
HashedCredentialsMatch
String hashAlgorithm,对于Hash接口的实现类。MD5
int hashIterations Hash迭代次数
boolean hashSalted 已过时,不用设置
boolean storedCredentialsHexEncoded 设置默认的true
加盐加密:
需要在认证返回的认证信息SimpleAuthenticationInfo中,指定需要加的盐salt,这样算出来的密文才可以和数据库中的密文进行比对
初次注册对密码落库加密
SimpleHash simpleHash=newSimpleHash(“MD5”,ByteSource.Util.bytes(password),ByteSource.Util.bytes(“salt”),3);
注意:字符串转ByteSource对象,ByteSource source=ByteSource.Util.bytes(“salt”);
9:多realm数据源认证
实现登录名,手机号,邮箱都可以登录功能
可以定义多个Realm完成不同的登录功能
我们通过增加一个phoneRealm,就实现了手机号登录的功能
1:创建PhoneRealm继承AuthenticatingRealm,只需要认证就行,在MyReaml中已经实现过授权
2:在PhoneRealm中重写doGetAuthenticationInfo方法,可照搬MyRealm中的doGetAuthenticationInfo方法,修改一下获取用户名改为获取电话就行
3:三板斧的SecurityManger在流程控制的方法参数添加AuthenticatingRealm phoneRealm;
方法体中设置加密规则;
DefultSecurityManager securityManager=new DefultSecurityManager();
HashedCredentialsMatcher matcher=new HashedCredentialsMatcher();
matcher.setHashAlgorithmName(“MD5”);
matcher.setHashIterations(3);
myRealm.setCredentialsMatcher(matcher);//这是用户名Reaml
phoneRealm.setCredentialsmatch(matcher);//这是电话号码的Reaml
securityManager.setReamls(Arrays.asList(myRealm,phoneRealm))//可以做一个或者集合
4:多Realm的认证策略:
AuthenticationStrategy接口有三个实现类
AllSuccessfulStrategy:需要所以Realm认证成功,才能最终认证成功
AtLeastOneSuccessfulStrategy:(默认策略)至少有一个Realm认证成功,才能最终认证成功
FirstSuccessfulStrategy:第一个Realm认证成功后即返回认证成功,不再进行后面的Realm认证
设置认策略:在三板斧的SecurityManger在流程控制的设置
ModularRealmAuthenticator authenticator =new ModularRealmAuthenticato();
authenticator.setAuthenticationStrategy(new AllSuccessfulStrategy());
authenticator.setRealms(Arrays.asList(myRealm,phoneRealm));
securityManager.setAuthenticator(authenticator );
10:下面这两个是要在分布式部署中实现状态共享需要改造的地方
1:记住我功能
遇到的坑,调试了一个下午
1:记住我功能是在本地浏览器生成cookie保存的
2:subject.isAuthenticated()和subject.isRemembered()同时只能一个为true
3:subject.isAuthenticated()保存的的是session,seesion有就会当浏览器已关闭seesion就没有了,subject.isRemembered()保存的是cookie,cookie可以设置存活时长,保存在浏览器本地,关闭浏览器不会取消,到期才会取消。也可以设置cookie时间为cookie.setMaxAge(60),默认是-1 关闭浏览器失效。
3:第一次访问的成功登录后,只要不关闭浏览器isAuthenticated()一直为true
4:关闭浏览器重启打开,去登陆判断的时候subject.isAuthenticated()就会为false,subject.isAuthenticated()根据cookie存活在为true,否则为false
5:使用shiro注解生效一定要在shiroConfig注入三个bean,才能管理shiro注解生命周期,LifecycleBeanPostProcessor,DefaultAdvisorAutoProxyCreator,AuthorizationAttributeSourceAdvisor
6:使用记住我功能是为了没有session通过cookie访问资源,可以在shiroFilterFactoryBean中配置("/pass/", “user”),或者直接在方法上加上注解@RequiresUser(不知为何这个注解一直不生效,所以用@RequiresPermissions(pass:)同样可实现一样的功能)
UsernamePasswordToke token=new UsernamePasswordToke(user.getName(),user.getPassword());
token.isRememberMe();//是否记住我
token.setRemembeMe(true);
记住我功能对应了默认的user过滤器(就是需要记住我user过滤器才生效,如果没有记住我,就是登录了也不生效)
设置记住我时长和保存在哪里
三板斧的SecurityManger在流程控制的方法中设置
CookieRememberMeManager rememberMeManager=new CookieRememberMeManager();
Cookie cookie=new SimpleCookie(“rememberMe”);
cookie.setHttpOnly(true);
cookie.setMaxAge(5);//设置时长单位为秒
rememberMeManager.setCookie(cookie);
securityManager.setRememberMeManager(rememberMeManager);
多服务器之间怎么共享cookie和sesion,访问一定是通过nginx进行负载均衡的,所以可以在nginx安装redis进行数据共享cookie和sesion,还有一种是直接落库到数据库,但是这样方式耗性能
2:回话管理
使用和cookie设置类似
securityManager.setSessionManager(sessionManager);
3:认证缓存(认同通过后,后面就不进认证器查数据了)
MemoryConstrainedCacheManagercacheManager=new MemoryConstrainedCacheManager();
securityManager.setCacheManager(cacheManager);
记住我,会话管理以及认证缓存,都可以通过扩展对应的manager接口的方式,实现自己的灵活扩展,比如将信息共享到redis