[Java from Zero to Architect Season 3] [49] Session Management - Token_ehcache

lpruoyu 2022-08-06 20:02:55 阅读数:329

javazeroarchitectseasonsession

持续学习&持续更新中…

守破离


基于Cookie、Session

在这里插入图片描述

在这里插入图片描述

基于Token

在这里插入图片描述

在这里插入图片描述

ehcache

简单使用

在这里插入图片描述

依赖:

 <!-- 缓存 -->
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>

标签:

 <!-- <persistence directory="F:/ehcache"/> -->
<cache alias="test">
<expiry>
<!-- none:永不过期 -->
<none/>
<!-- tti:time to idle(空闲时间)=> 10月1号登录,默认10月8number will be invalid. 但是,如果10月3号登陆了,那么10月10number is invalid; 如果10月4logged in again,Then extend it7天,10月11number is invalid. 也就是说,只要7天内不访问,就失效. -->
<!-- <tti unit="days">7</tti> -->
<!-- ttl:time to live(存活时间)=> 10月1号登录,10月8number will be invalid -->
<!-- <ttl unit="days">7</ttl> -->
</expiry>
<resources>
<!-- <offheap unit="MB"/> 堆外内存 -->
<!-- <disk unit="MB" persistent="true" /> 磁盘 需要搭配persistence标签 -->
<heap unit="entries">1000</heap> <!-- into heap memory,In-heap memory isnewwhere the objects are stored -->
<!-- <heap>1000</heap> unit="entries" 缓存个数 是默认的 -->
<!-- <heap unit="MB">1000</heap> 缓存大小:GB、MB、KB、... -->
</resources>
</cache>

使用:

<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns='http://www.ehcache.org/v3' xsi:schemaLocation="http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core.xsd">
<cache-template name="common">
<key-type>java.lang.Object</key-type>
<value-type>java.lang.Object</value-type>
<resources>
<heap>10000</heap>
</resources>
</cache-template>
<!-- 11月1号~11月7号,11月8号过期 11月6号~11月12号,11月13号过期 11月12号~11月18号,11月19号过期 -->
<!-- 存放token的缓存:只要7天内不访问,就失效 -->
<cache alias="token" uses-template="common">
<expiry>
<tti unit="days">7</tti>
</expiry>
</cache>
<!-- 默认缓存:永不过期 -->
<cache alias="default" uses-template="common">
<expiry>
<none/>
</expiry>
</cache>
</config>
public class Caches {

private static final CacheManager MGR;
private static final Cache<Object, Object> DEFAULT_CACHE;
private static final Cache<Object, Object> TOKEN_CACHE;
static {

// 初始化缓存管理器
URL url = Caches.class.getClassLoader().getResource("ehcache.xml");
assert url != null;
Configuration cfg = new XmlConfiguration(url);
MGR = CacheManagerBuilder.newCacheManager(cfg);
MGR.init();
// 缓存对象
DEFAULT_CACHE = MGR.getCache("default", Object.class, Object.class);
TOKEN_CACHE = MGR.getCache("token", Object.class, Object.class);
}
public static void put(Object key, Object value) {

if (key == null || value == null) return;
DEFAULT_CACHE.put(key, value);
}
public static void remove(Object key) {

if (key == null) return;
DEFAULT_CACHE.remove(key);
}
public static <T> T get(Object key) {

if (key == null) return null;
return (T) DEFAULT_CACHE.get(key);
}
public static void clear() {

DEFAULT_CACHE.clear();
}
public static void putToken(Object key, Object value) {

if (key == null || value == null) return;
TOKEN_CACHE.put(key, value);
}
public static void removeToken(Object key) {

if (key == null) return;
TOKEN_CACHE.remove(key);
}
public static <T> T getToken(Object key) {

if (key == null) return null;
return (T) TOKEN_CACHE.get(key);
}
public static void clearToken() {

TOKEN_CACHE.clear();
}
}

项目使用:登录、登出

  • as long as7logged in days,就不会失效,就不用重新登录
<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns='http://www.ehcache.org/v3' xsi:schemaLocation="http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core.xsd">
<cache-template name="common">
<key-type>java.lang.Object</key-type>
<value-type>java.lang.Object</value-type>
<resources>
<heap>10000</heap>
</resources>
</cache-template>
<!-- 11月1号~11月7号,11月8号过期 11月6号~11月12号,11月13号过期 11月12号~11月18号,11月19号过期 -->
<!-- 存放token的缓存:只要7天内不访问,就失效 -->
<cache alias="token" uses-template="common">
<expiry>
<tti unit="days">7</tti>
<!-- <tti unit="seconds">7</tti>-->
</expiry>
<listeners>
<listener>
<class>programmer.lp.jk.common.cache.TokenCacheListener</class>
<!-- 异步回调 -->
<event-firing-mode>ASYNCHRONOUS</event-firing-mode>
<!-- Don't process events sequentially -->
<event-ordering-mode>UNORDERED</event-ordering-mode>
<!-- Which actions will trigger the listener:添加、过期、删除 -->
<events-to-fire-on>CREATED</events-to-fire-on>
<events-to-fire-on>EXPIRED</events-to-fire-on>
<events-to-fire-on>REMOVED</events-to-fire-on>
</listener>
</listeners>
</cache>
<!-- 默认缓存:永不过期 -->
<cache alias="default" uses-template="common">
<expiry>
<none/>
</expiry>
</cache>
</config>
public class TokenCacheListener implements CacheEventListener<Object, Object> {

@Override
public void onEvent(CacheEvent cacheEvent) {

String token = (String) cacheEvent.getKey();
switch (cacheEvent.getType()) {

case CREATED: {
// 添加了一个新的token(Indicates that a user has just logged in)
SysUserDto user = (SysUserDto) cacheEvent.getNewValue();
// for future pass usersid找到他对应的token
Caches.put(user.getUser().getId(), token);
break;
}
case EXPIRED:
case REMOVED: {
 // tokenremoved or expired
SysUserDto user = (SysUserDto) cacheEvent.getOldValue();
Caches.remove(user.getUser().getId());
break;
}
default: break;
}
}
}
@Override
public RespLogin login(ReqLogin reqVo) {

// 根据用户名查询用户
MPLambdaQueryWrapper<SysUser> wrapper = new MPLambdaQueryWrapper<>();
wrapper.eq(SysUser::getUsername, reqVo.getUsername());
SysUser po = baseMapper.selectOne(wrapper);
// 用户名不存在
if (po == null) {

return JSONResults.exception(CodeMsg.WRONG_USERNAME);
}
// 密码不正确
if (!po.getPassword().equals(reqVo.getPassword())) {

return JSONResults.exception(CodeMsg.WRONG_PASSWORD);
}
// 账号锁定
if (po.getStatus() == Constants.SysUserStatus.LOCKED) {

return JSONResults.exception(CodeMsg.USER_LOCKED);
}
/** 登录成功 **/
// 更新登录时间
po.setLoginTime(new Date());
baseMapper.updateById(po);
SysUserDto dto = new SysUserDto();
dto.setUser(po);
// 根据用户id查询所有的角色:sys_role,sys_user_role
List<SysRole> roles = roleService.listByUserId(po.getId());
// 根据角色id查询所有的资源:sys_resource、sys_role_resource
if (!CollectionUtils.isEmpty(roles)) {

dto.setRoles(roles);
List<Short> roleIds = Streams.map(roles, SysRole::getId);
List<SysResource> resources = resourceService.listByRoleIds(roleIds);
dto.setResources(resources);
}
// 生成Token,发送Token给用户
String token = UUID.randomUUID().toString();
// 存储token到缓存中
Caches.putToken(token, dto);
// Specific data returned to the client
RespLogin vo = MapStruct.INSTANCE.po2loginVo(po);
vo.setToken(token);
return vo;
}
 @PostMapping("/logout")
@ApiOperation("退出登录")
public JSONResult logout(@RequestHeader(TokenFilter.HEADER_TOKEN) String token) {

Caches.removeToken(token);
return JSONResults.ok(CodeMsg.LOGOUT_OK);
}
 @Override
public boolean saveOrUpdate(ReqSaveSysUser entity) {

// 转成PO
SysUser po = MapStruct.INSTANCE.vo2po(entity);
// 保存用户信息
if (!saveOrUpdate(po)) return false;
Integer id = entity.getId();
if (id != null && id > 0) {
// If it is an update
// Remove successfully updated users from the cache(让token失效,用户必须重新登录)
Caches.removeToken(Caches.get(id));
// Caches.remove(id);
// Deletes all role information for the current user
userRoleService.removeByUserId(entity.getId());
}
// 保存角色信息
String roleIdsStr = entity.getRoleIds();
if (Strings.isEmpty(roleIdsStr)) return true;
String[] roleIds = roleIdsStr.split(",");
List<SysUserRole> userRoles = new ArrayList<>();
Integer userId = po.getId();
for (String roleId : roleIds) {
 // 构建SysUserRole对象
SysUserRole userRole = new SysUserRole();
userRole.setUserId(userId);
userRole.setRoleId(Short.parseShort(roleId));
userRoles.add(userRole);
}
return userRoleService.saveBatch(userRoles);
}
// If the role information is updated, the user must log in again.
// Re-login is to check the user's permissions(资源),Let it cooperateShiro使用
@Override
public boolean saveOrUpdate(ReqSaveSysRole entity) {

// 转成PO
SysRole po = MapStruct.INSTANCE.vo2po(entity);
// 保存角色信息
if (!saveOrUpdate(po)) return false;
Short id = entity.getId();
if (id != null && id > 0) {

MPLambdaQueryWrapper<SysUserRole> wrapper = new MPLambdaQueryWrapper<>();
wrapper.select(SysUserRole::getUserId);
wrapper.eq(SysUserRole::getRoleId, id);
List<Object> userIds = userRoleMapper.selectObjs(wrapper);
if (!CollectionUtils.isEmpty(userIds)) {

for (Object userId : userIds) {

// Removes users with this role from the cache(让token失效,用户必须重新登录)
Caches.removeToken(Caches.get(userId));
}
}
// Deletes all resource information for the current role
roleResourceService.removeByRoleId(id);
}
// 保存角色信息
String resourceIdsStr = entity.getResourceIds();
if (Strings.isEmpty(resourceIdsStr)) return true;
String[] resourceIds = resourceIdsStr.split(",");
List<SysRoleResource> roleResources = new ArrayList<>();
Short roleId = po.getId();
for (String resourceId : resourceIds) {
 // 构建SysUserRole对象
SysRoleResource roleResource = new SysRoleResource();
roleResource.setRoleId(roleId);
roleResource.setResourceId(Short.parseShort(resourceId));
roleResources.add(roleResource);
}
return roleResourceService.saveBatch(roleResources);
}

补充:A simple introduction to distributed architecture

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

参考

小码哥-李明杰: Java从0到架构师③进阶互联网架构师.


本文完,感谢您的关注支持!


copyright:author[lpruoyu],Please bring the original link to reprint, thank you. https://en.javamana.com/2022/218/202208061954591586.html