优化生成token逻辑

This commit is contained in:
阿沐 2023-08-09 23:27:41 +08:00
parent bf5a15add3
commit ede7382256
18 changed files with 570 additions and 108 deletions

View File

@ -2,6 +2,7 @@ package net.maku.security.service;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import net.maku.framework.security.mobile.MobileUserDetailsService; import net.maku.framework.security.mobile.MobileUserDetailsService;
import net.maku.system.convert.SysUserConvert;
import net.maku.system.dao.SysUserDao; import net.maku.system.dao.SysUserDao;
import net.maku.system.entity.SysUserEntity; import net.maku.system.entity.SysUserEntity;
import net.maku.system.service.SysUserDetailsService; import net.maku.system.service.SysUserDetailsService;
@ -28,7 +29,7 @@ public class MobileUserDetailsServiceImpl implements MobileUserDetailsService {
throw new UsernameNotFoundException("手机号或验证码错误"); throw new UsernameNotFoundException("手机号或验证码错误");
} }
return sysUserDetailsService.getUserDetails(userEntity); return sysUserDetailsService.getUserDetails(SysUserConvert.INSTANCE.convertDetail(userEntity));
} }
} }

View File

@ -1,6 +1,7 @@
package net.maku.security.service; package net.maku.security.service;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import net.maku.system.convert.SysUserConvert;
import net.maku.system.dao.SysUserDao; import net.maku.system.dao.SysUserDao;
import net.maku.system.entity.SysUserEntity; import net.maku.system.entity.SysUserEntity;
import net.maku.system.service.SysUserDetailsService; import net.maku.system.service.SysUserDetailsService;
@ -28,7 +29,7 @@ public class UserDetailsServiceImpl implements UserDetailsService {
throw new UsernameNotFoundException("用户名或密码错误"); throw new UsernameNotFoundException("用户名或密码错误");
} }
return sysUserDetailsService.getUserDetails(userEntity); return sysUserDetailsService.getUserDetails(SysUserConvert.INSTANCE.convertDetail(userEntity));
} }
} }

View File

@ -0,0 +1,21 @@
package net.maku.system.convert;
import net.maku.system.entity.SysUserTokenEntity;
import net.maku.system.vo.SysUserTokenVO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
/**
* 用户Token
*
* @author 阿沐 babamu@126.com
*/
@Mapper
public interface SysUserTokenConvert {
SysUserTokenConvert INSTANCE = Mappers.getMapper(SysUserTokenConvert.class);
SysUserTokenEntity convert(SysUserTokenVO vo);
SysUserTokenVO convert(SysUserTokenEntity entity);
}

View File

@ -5,6 +5,8 @@ import net.maku.system.entity.SysRoleEntity;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import java.util.List;
/** /**
* 角色管理 * 角色管理
* *
@ -19,4 +21,9 @@ public interface SysRoleDao extends BaseDao<SysRoleEntity> {
*/ */
Integer getDataScopeByUserId(@Param("userId") Long userId); Integer getDataScopeByUserId(@Param("userId") Long userId);
/**
* 根据用户ID获取用户角色编码
*/
List<String> geRoleCodeByUserId(@Param("userId") Long userId);
} }

View File

@ -0,0 +1,37 @@
package net.maku.system.dao;
import net.maku.framework.mybatis.dao.BaseDao;
import net.maku.system.entity.SysUserTokenEntity;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.Date;
import java.util.List;
/**
* 用户Token
*
* @author 阿沐 babamu@126.com
*/
@Mapper
public interface SysUserTokenDao extends BaseDao<SysUserTokenEntity> {
/**
* 根据角色ID查询在线用户 access_token 列表
*
* @param roleId 角色ID
* @param time 当前时间
* @return 返回 access_token 列表
*/
List<String> getOnlineAccessTokenListByRoleId(@Param("roleId") Long roleId, @Param("time") Date time);
/**
* 根据用户ID查询在线用户 access_token 列表
*
* @param userId 用户ID
* @param time 当前时间
* @return 返回 access_token 列表
*/
List<String> getOnlineAccessTokenListByUserId(@Param("userId") Long userId, @Param("time") Date time);
}

View File

@ -0,0 +1,61 @@
package net.maku.system.entity;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.util.Date;
/**
* 用户Token
*
* @author 阿沐 babamu@126.com
* <a href="https://maku.net">MAKU</a>
*/
@Data
@TableName("sys_user_token")
public class SysUserTokenEntity {
@TableId
private Long id;
/**
* 用户ID
*/
private Long userId;
/**
* accessToken
*/
private String accessToken;
/**
* accessToken 过期时间
*/
private Date accessTokenExpire;
/**
* refreshToken
*/
private String refreshToken;
/**
* refreshToken 过期时间
*/
private Date refreshTokenExpire;
/**
* 租户ID
*/
private Long tenantId;
/**
* 创建时间
*/
@TableField(fill = FieldFill.INSERT)
private Date createTime;
}

View File

@ -1,8 +1,9 @@
package net.maku.system.service; package net.maku.system.service;
import net.maku.system.vo.AccessTokenVO;
import net.maku.system.vo.SysAccountLoginVO; import net.maku.system.vo.SysAccountLoginVO;
import net.maku.system.vo.SysMobileLoginVO; import net.maku.system.vo.SysMobileLoginVO;
import net.maku.system.vo.SysTokenVO; import net.maku.system.vo.SysUserTokenVO;
/** /**
* 权限认证服务 * 权限认证服务
@ -17,14 +18,14 @@ public interface SysAuthService {
* *
* @param login 登录信息 * @param login 登录信息
*/ */
SysTokenVO loginByAccount(SysAccountLoginVO login); SysUserTokenVO loginByAccount(SysAccountLoginVO login);
/** /**
* 手机短信登录 * 手机短信登录
* *
* @param login 登录信息 * @param login 登录信息
*/ */
SysTokenVO loginByMobile(SysMobileLoginVO login); SysUserTokenVO loginByMobile(SysMobileLoginVO login);
/** /**
* 发送手机验证码 * 发送手机验证码
@ -34,6 +35,13 @@ public interface SysAuthService {
boolean sendCode(String mobile); boolean sendCode(String mobile);
/** /**
* 根据刷新Token获取AccessToken
*
* @param refreshToken refreshToken
*/
AccessTokenVO getAccessToken(String refreshToken);
/**
* 退出登录 * 退出登录
* *
* @param accessToken accessToken * @param accessToken accessToken

View File

@ -1,12 +1,12 @@
package net.maku.system.service; package net.maku.system.service;
import net.maku.system.entity.SysUserEntity; import net.maku.framework.security.user.UserDetail;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
public interface SysUserDetailsService { public interface SysUserDetailsService {
/** /**
* 获取 UserDetails 对象 * 获取 UserDetails 对象设置用户权限信息
*/ */
UserDetails getUserDetails(SysUserEntity userEntity); UserDetails getUserDetails(UserDetail userDetail);
} }

View File

@ -0,0 +1,51 @@
package net.maku.system.service;
import net.maku.framework.mybatis.service.BaseService;
import net.maku.system.entity.SysUserTokenEntity;
import net.maku.system.vo.SysUserTokenVO;
/**
* 用户Token
*
* @author 阿沐 babamu@126.com
*/
public interface SysUserTokenService extends BaseService<SysUserTokenEntity> {
/**
* 根据用户ID生成用户Token
*
* @param userId 用户ID
* @return 用户Token
*/
SysUserTokenVO createToken(Long userId);
/**
* 根据refreshToken生成新Token
*
* @param refreshToken refreshToken
* @return 用户Token
*/
SysUserTokenVO refreshToken(String refreshToken);
/**
* Token过期
*
* @param userId 用户ID
*/
void expireToken(Long userId);
/**
* 根据角色ID更新用户缓存权限
*
* @param roleId 角色ID
*/
void updateCacheAuthByRoleId(Long roleId);
/**
* 根据用户ID更新用户缓存权限
*
* @param userId 用户ID
*/
void updateCacheAuthByUserId(Long userId);
}

View File

@ -8,16 +8,9 @@ import net.maku.framework.common.exception.ServerException;
import net.maku.framework.security.cache.TokenStoreCache; import net.maku.framework.security.cache.TokenStoreCache;
import net.maku.framework.security.mobile.MobileAuthenticationToken; import net.maku.framework.security.mobile.MobileAuthenticationToken;
import net.maku.framework.security.user.UserDetail; import net.maku.framework.security.user.UserDetail;
import net.maku.framework.security.utils.TokenUtils;
import net.maku.system.enums.LoginOperationEnum; import net.maku.system.enums.LoginOperationEnum;
import net.maku.system.service.SysAuthService; import net.maku.system.service.*;
import net.maku.system.service.SysCaptchaService; import net.maku.system.vo.*;
import net.maku.system.service.SysLogLoginService;
import net.maku.system.service.SysUserService;
import net.maku.system.vo.SysAccountLoginVO;
import net.maku.system.vo.SysMobileLoginVO;
import net.maku.system.vo.SysTokenVO;
import net.maku.system.vo.SysUserVO;
import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@ -38,10 +31,11 @@ public class SysAuthServiceImpl implements SysAuthService {
private final AuthenticationManager authenticationManager; private final AuthenticationManager authenticationManager;
private final SysLogLoginService sysLogLoginService; private final SysLogLoginService sysLogLoginService;
private final SysUserService sysUserService; private final SysUserService sysUserService;
private final SysUserTokenService sysUserTokenService;
private final SmsApi smsApi; private final SmsApi smsApi;
@Override @Override
public SysTokenVO loginByAccount(SysAccountLoginVO login) { public SysUserTokenVO loginByAccount(SysAccountLoginVO login) {
// 验证码效验 // 验证码效验
boolean flag = sysCaptchaService.validate(login.getKey(), login.getCaptcha()); boolean flag = sysCaptchaService.validate(login.getKey(), login.getCaptcha());
if (!flag) { if (!flag) {
@ -64,16 +58,16 @@ public class SysAuthServiceImpl implements SysAuthService {
UserDetail user = (UserDetail) authentication.getPrincipal(); UserDetail user = (UserDetail) authentication.getPrincipal();
// 生成 accessToken // 生成 accessToken
String accessToken = TokenUtils.generator(); SysUserTokenVO userTokenVO = sysUserTokenService.createToken(user.getId());
// 保存用户信息到缓存 // 保存用户信息到缓存
tokenStoreCache.saveUser(accessToken, user); tokenStoreCache.saveUser(userTokenVO.getAccessToken(), user);
return new SysTokenVO(accessToken); return userTokenVO;
} }
@Override @Override
public SysTokenVO loginByMobile(SysMobileLoginVO login) { public SysUserTokenVO loginByMobile(SysMobileLoginVO login) {
Authentication authentication; Authentication authentication;
try { try {
// 用户认证 // 用户认证
@ -87,12 +81,12 @@ public class SysAuthServiceImpl implements SysAuthService {
UserDetail user = (UserDetail) authentication.getPrincipal(); UserDetail user = (UserDetail) authentication.getPrincipal();
// 生成 accessToken // 生成 accessToken
String accessToken = TokenUtils.generator(); SysUserTokenVO userTokenVO = sysUserTokenService.createToken(user.getId());
// 保存用户信息到缓存 // 保存用户信息到缓存
tokenStoreCache.saveUser(accessToken, user); tokenStoreCache.saveUser(userTokenVO.getAccessToken(), user);
return new SysTokenVO(accessToken); return userTokenVO;
} }
@Override @Override
@ -110,6 +104,18 @@ public class SysAuthServiceImpl implements SysAuthService {
} }
@Override @Override
public AccessTokenVO getAccessToken(String refreshToken) {
SysUserTokenVO token = sysUserTokenService.refreshToken(refreshToken);
// 封装 AccessToken
AccessTokenVO accessToken = new AccessTokenVO();
accessToken.setAccessToken(token.getAccessToken());
accessToken.setAccessTokenExpire(token.getAccessTokenExpire());
return accessToken;
}
@Override
public void logout(String accessToken) { public void logout(String accessToken) {
// 用户信息 // 用户信息
UserDetail user = tokenStoreCache.getUser(accessToken); UserDetail user = tokenStoreCache.getUser(accessToken);
@ -117,6 +123,9 @@ public class SysAuthServiceImpl implements SysAuthService {
// 删除用户信息 // 删除用户信息
tokenStoreCache.deleteUser(accessToken); tokenStoreCache.deleteUser(accessToken);
// Token过期
sysUserTokenService.expireToken(user.getId());
// 保存登录日志 // 保存登录日志
sysLogLoginService.save(user.getUsername(), Constant.SUCCESS, LoginOperationEnum.LOGOUT_SUCCESS.getValue()); sysLogLoginService.save(user.getUsername(), Constant.SUCCESS, LoginOperationEnum.LOGOUT_SUCCESS.getValue());
} }

View File

@ -12,10 +12,7 @@ import net.maku.system.dao.SysRoleDao;
import net.maku.system.entity.SysRoleEntity; import net.maku.system.entity.SysRoleEntity;
import net.maku.system.enums.DataScopeEnum; import net.maku.system.enums.DataScopeEnum;
import net.maku.system.query.SysRoleQuery; import net.maku.system.query.SysRoleQuery;
import net.maku.system.service.SysRoleDataScopeService; import net.maku.system.service.*;
import net.maku.system.service.SysRoleMenuService;
import net.maku.system.service.SysRoleService;
import net.maku.system.service.SysUserRoleService;
import net.maku.system.vo.SysRoleDataScopeVO; import net.maku.system.vo.SysRoleDataScopeVO;
import net.maku.system.vo.SysRoleVO; import net.maku.system.vo.SysRoleVO;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -36,6 +33,7 @@ public class SysRoleServiceImpl extends BaseServiceImpl<SysRoleDao, SysRoleEntit
private final SysRoleMenuService sysRoleMenuService; private final SysRoleMenuService sysRoleMenuService;
private final SysRoleDataScopeService sysRoleDataScopeService; private final SysRoleDataScopeService sysRoleDataScopeService;
private final SysUserRoleService sysUserRoleService; private final SysUserRoleService sysUserRoleService;
private final SysUserTokenService sysUserTokenService;
@Override @Override
public PageResult<SysRoleVO> page(SysRoleQuery query) { public PageResult<SysRoleVO> page(SysRoleQuery query) {
@ -84,6 +82,9 @@ public class SysRoleServiceImpl extends BaseServiceImpl<SysRoleDao, SysRoleEntit
// 更新角色菜单关系 // 更新角色菜单关系
sysRoleMenuService.saveOrUpdate(entity.getId(), vo.getMenuIdList()); sysRoleMenuService.saveOrUpdate(entity.getId(), vo.getMenuIdList());
// 更新角色对应用户的缓存权限
sysUserTokenService.updateCacheAuthByRoleId(entity.getId());
} }
@Override @Override
@ -100,6 +101,9 @@ public class SysRoleServiceImpl extends BaseServiceImpl<SysRoleDao, SysRoleEntit
} else { } else {
sysRoleDataScopeService.deleteByRoleIdList(Collections.singletonList(vo.getId())); sysRoleDataScopeService.deleteByRoleIdList(Collections.singletonList(vo.getId()));
} }
// 更新角色对应用户的缓存权限
sysUserTokenService.updateCacheAuthByRoleId(entity.getId());
} }
@Override @Override
@ -116,6 +120,9 @@ public class SysRoleServiceImpl extends BaseServiceImpl<SysRoleDao, SysRoleEntit
// 删除角色数据权限关系 // 删除角色数据权限关系
sysRoleDataScopeService.deleteByRoleIdList(idList); sysRoleDataScopeService.deleteByRoleIdList(idList);
// 更新角色对应用户的缓存权限
idList.forEach(sysUserTokenService::updateCacheAuthByRoleId);
} }
} }

View File

@ -2,10 +2,8 @@ package net.maku.system.service.impl;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import net.maku.framework.security.user.UserDetail; import net.maku.framework.security.user.UserDetail;
import net.maku.system.convert.SysUserConvert;
import net.maku.system.dao.SysRoleDao; import net.maku.system.dao.SysRoleDao;
import net.maku.system.dao.SysRoleDataScopeDao; import net.maku.system.dao.SysRoleDataScopeDao;
import net.maku.system.entity.SysUserEntity;
import net.maku.system.enums.DataScopeEnum; import net.maku.system.enums.DataScopeEnum;
import net.maku.system.enums.UserStatusEnum; import net.maku.system.enums.UserStatusEnum;
import net.maku.system.service.SysMenuService; import net.maku.system.service.SysMenuService;
@ -33,12 +31,9 @@ public class SysUserDetailsServiceImpl implements SysUserDetailsService {
private final SysRoleDataScopeDao sysRoleDataScopeDao; private final SysRoleDataScopeDao sysRoleDataScopeDao;
@Override @Override
public UserDetails getUserDetails(SysUserEntity userEntity) { public UserDetails getUserDetails(UserDetail userDetail) {
// 转换成UserDetail对象
UserDetail userDetail = SysUserConvert.INSTANCE.convertDetail(userEntity);
// 账号不可用 // 账号不可用
if (userEntity.getStatus() == UserStatusEnum.DISABLE.getValue()) { if (userDetail.getStatus() == UserStatusEnum.DISABLE.getValue()) {
userDetail.setEnabled(false); userDetail.setEnabled(false);
} }
@ -48,6 +43,11 @@ public class SysUserDetailsServiceImpl implements SysUserDetailsService {
// 用户权限列表 // 用户权限列表
Set<String> authoritySet = sysMenuService.getUserAuthority(userDetail); Set<String> authoritySet = sysMenuService.getUserAuthority(userDetail);
// 用户角色编码列表
List<String> roleCodeList = sysRoleDao.geRoleCodeByUserId(userDetail.getId());
roleCodeList.forEach(roleCode -> authoritySet.add("ROLE_" + roleCode));
userDetail.setAuthoritySet(authoritySet); userDetail.setAuthoritySet(authoritySet);
return userDetail; return userDetail;

View File

@ -2,10 +2,12 @@ package net.maku.system.service.impl;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.AllArgsConstructor;
import net.maku.framework.mybatis.service.impl.BaseServiceImpl; import net.maku.framework.mybatis.service.impl.BaseServiceImpl;
import net.maku.system.dao.SysUserRoleDao; import net.maku.system.dao.SysUserRoleDao;
import net.maku.system.entity.SysUserRoleEntity; import net.maku.system.entity.SysUserRoleEntity;
import net.maku.system.service.SysUserRoleService; import net.maku.system.service.SysUserRoleService;
import net.maku.system.service.SysUserTokenService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.Collection; import java.util.Collection;
@ -19,7 +21,9 @@ import java.util.stream.Collectors;
* <a href="https://maku.net">MAKU</a> * <a href="https://maku.net">MAKU</a>
*/ */
@Service @Service
@AllArgsConstructor
public class SysUserRoleServiceImpl extends BaseServiceImpl<SysUserRoleDao, SysUserRoleEntity> implements SysUserRoleService { public class SysUserRoleServiceImpl extends BaseServiceImpl<SysUserRoleDao, SysUserRoleEntity> implements SysUserRoleService {
private final SysUserTokenService sysUserTokenService;
@Override @Override
public void saveOrUpdate(Long userId, List<Long> roleIdList) { public void saveOrUpdate(Long userId, List<Long> roleIdList) {
@ -59,6 +63,9 @@ public class SysUserRoleServiceImpl extends BaseServiceImpl<SysUserRoleDao, SysU
// 批量新增 // 批量新增
saveBatch(list); saveBatch(list);
// 更新用户的缓存权限
userIdList.forEach(sysUserTokenService::updateCacheAuthByUserId);
} }
@Override @Override
@ -75,6 +82,9 @@ public class SysUserRoleServiceImpl extends BaseServiceImpl<SysUserRoleDao, SysU
public void deleteByUserIdList(Long roleId, List<Long> userIdList) { public void deleteByUserIdList(Long roleId, List<Long> userIdList) {
LambdaQueryWrapper<SysUserRoleEntity> queryWrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<SysUserRoleEntity> queryWrapper = new LambdaQueryWrapper<>();
remove(queryWrapper.eq(SysUserRoleEntity::getRoleId, roleId).in(SysUserRoleEntity::getUserId, userIdList)); remove(queryWrapper.eq(SysUserRoleEntity::getRoleId, roleId).in(SysUserRoleEntity::getUserId, userIdList));
// 更新用户的缓存权限
userIdList.forEach(sysUserTokenService::updateCacheAuthByUserId);
} }
@Override @Override

View File

@ -8,10 +8,10 @@ import lombok.SneakyThrows;
import net.maku.framework.common.constant.Constant; import net.maku.framework.common.constant.Constant;
import net.maku.framework.common.excel.ExcelFinishCallBack; import net.maku.framework.common.excel.ExcelFinishCallBack;
import net.maku.framework.common.exception.ServerException; import net.maku.framework.common.exception.ServerException;
import net.maku.framework.common.utils.PageResult;
import net.maku.framework.mybatis.service.impl.BaseServiceImpl;
import net.maku.framework.common.utils.DateUtils; import net.maku.framework.common.utils.DateUtils;
import net.maku.framework.common.utils.ExcelUtils; import net.maku.framework.common.utils.ExcelUtils;
import net.maku.framework.common.utils.PageResult;
import net.maku.framework.mybatis.service.impl.BaseServiceImpl;
import net.maku.system.convert.SysUserConvert; import net.maku.system.convert.SysUserConvert;
import net.maku.system.dao.SysUserDao; import net.maku.system.dao.SysUserDao;
import net.maku.system.entity.SysUserEntity; import net.maku.system.entity.SysUserEntity;
@ -21,6 +21,7 @@ import net.maku.system.query.SysUserQuery;
import net.maku.system.service.SysUserPostService; import net.maku.system.service.SysUserPostService;
import net.maku.system.service.SysUserRoleService; import net.maku.system.service.SysUserRoleService;
import net.maku.system.service.SysUserService; import net.maku.system.service.SysUserService;
import net.maku.system.service.SysUserTokenService;
import net.maku.system.vo.SysUserExcelVO; import net.maku.system.vo.SysUserExcelVO;
import net.maku.system.vo.SysUserVO; import net.maku.system.vo.SysUserVO;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -43,6 +44,7 @@ import java.util.Map;
public class SysUserServiceImpl extends BaseServiceImpl<SysUserDao, SysUserEntity> implements SysUserService { public class SysUserServiceImpl extends BaseServiceImpl<SysUserDao, SysUserEntity> implements SysUserService {
private final SysUserRoleService sysUserRoleService; private final SysUserRoleService sysUserRoleService;
private final SysUserPostService sysUserPostService; private final SysUserPostService sysUserPostService;
private final SysUserTokenService sysUserTokenService;
private final TransService transService; private final TransService transService;
@Override @Override
@ -125,6 +127,9 @@ public class SysUserServiceImpl extends BaseServiceImpl<SysUserDao, SysUserEntit
// 更新用户岗位关系 // 更新用户岗位关系
sysUserPostService.saveOrUpdate(entity.getId(), vo.getPostIdList()); sysUserPostService.saveOrUpdate(entity.getId(), vo.getPostIdList());
// 更新用户缓存权限
sysUserTokenService.updateCacheAuthByUserId(entity.getId());
} }
@Override @Override

View File

@ -0,0 +1,155 @@
package net.maku.system.service.impl;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.AllArgsConstructor;
import net.maku.framework.common.exception.ErrorCode;
import net.maku.framework.common.exception.ServerException;
import net.maku.framework.mybatis.service.impl.BaseServiceImpl;
import net.maku.framework.security.cache.TokenStoreCache;
import net.maku.framework.security.properties.SecurityProperties;
import net.maku.framework.security.user.UserDetail;
import net.maku.framework.security.utils.TokenUtils;
import net.maku.system.convert.SysUserConvert;
import net.maku.system.convert.SysUserTokenConvert;
import net.maku.system.dao.SysUserDao;
import net.maku.system.dao.SysUserTokenDao;
import net.maku.system.entity.SysUserEntity;
import net.maku.system.entity.SysUserTokenEntity;
import net.maku.system.service.SysUserDetailsService;
import net.maku.system.service.SysUserTokenService;
import net.maku.system.vo.SysUserTokenVO;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.List;
/**
* 用户Token
*
* @author 阿沐 babamu@126.com
*/
@Service
@AllArgsConstructor
public class SysUserTokenServiceImpl extends BaseServiceImpl<SysUserTokenDao, SysUserTokenEntity> implements SysUserTokenService {
private final TokenStoreCache tokenStoreCache;
private final SysUserDetailsService sysUserDetailsService;
private final SecurityProperties securityProperties;
private final SysUserDao sysUserDao;
@Override
public SysUserTokenVO createToken(Long userId) {
// 生成token
String accessToken = TokenUtils.generator();
String refreshToken = TokenUtils.generator();
SysUserTokenEntity entity = new SysUserTokenEntity();
entity.setUserId(userId);
entity.setAccessToken(accessToken);
entity.setRefreshToken(refreshToken);
// 过期时间
Date now = new Date();
entity.setAccessTokenExpire(DateUtil.offsetSecond(now, securityProperties.getAccessTokenExpire()));
entity.setRefreshTokenExpire(DateUtil.offsetSecond(now, securityProperties.getRefreshTokenExpire()));
// 是否存在Token
SysUserTokenEntity tokenEntity = baseMapper.selectOne(new LambdaQueryWrapper<SysUserTokenEntity>().eq(SysUserTokenEntity::getUserId, userId));
if (tokenEntity == null) {
baseMapper.insert(entity);
} else {
entity.setId(tokenEntity.getId());
baseMapper.updateById(entity);
}
return SysUserTokenConvert.INSTANCE.convert(entity);
}
@Override
public SysUserTokenVO refreshToken(String refreshToken) {
LambdaQueryWrapper<SysUserTokenEntity> query = Wrappers.lambdaQuery();
query.eq(SysUserTokenEntity::getRefreshToken, refreshToken);
query.ge(SysUserTokenEntity::getRefreshTokenExpire, new Date());
// 不存在则表示refreshToken错误或者已过期
SysUserTokenEntity entity = baseMapper.selectOne(query);
if (entity == null) {
throw new ServerException(ErrorCode.REFRESH_TOKEN_INVALID);
}
// 删除缓存信息
tokenStoreCache.deleteUser(entity.getAccessToken());
// 生成新 accessToken
String accessToken = TokenUtils.generator();
entity.setAccessToken(accessToken);
entity.setAccessTokenExpire(DateUtil.offsetSecond(new Date(), securityProperties.getAccessTokenExpire()));
// 更新
baseMapper.updateById(entity);
// 设置用户权限信息
SysUserEntity user = sysUserDao.selectById(entity.getUserId());
UserDetail userDetail = SysUserConvert.INSTANCE.convertDetail(user);
sysUserDetailsService.getUserDetails(userDetail);
// 保存用户信息到缓存
tokenStoreCache.saveUser(accessToken, userDetail);
return SysUserTokenConvert.INSTANCE.convert(entity);
}
@Override
public void expireToken(Long userId) {
SysUserTokenEntity entity = new SysUserTokenEntity();
entity.setAccessTokenExpire(new Date());
entity.setRefreshTokenExpire(new Date());
baseMapper.update(entity, new LambdaQueryWrapper<SysUserTokenEntity>().eq(SysUserTokenEntity::getUserId, userId));
}
@Async
@Override
public void updateCacheAuthByRoleId(Long roleId) {
// 根据角色ID查询用户 access_token 列表
List<String> accessTokenList = baseMapper.getOnlineAccessTokenListByRoleId(roleId, new Date());
accessTokenList.forEach(this::updateCacheAuth);
}
@Async
@Override
public void updateCacheAuthByUserId(Long userId) {
// 根据用户ID查询用户 access_token 列表
List<String> accessTokenList = baseMapper.getOnlineAccessTokenListByUserId(userId, new Date());
accessTokenList.forEach(this::updateCacheAuth);
}
/**
* 根据accessToken更新Cache里面的用户权限
*
* @param accessToken access_token
*/
private void updateCacheAuth(String accessToken) {
UserDetail user = tokenStoreCache.getUser(accessToken);
// 用户不存在
if (user == null) {
return;
}
// 查询过期时间
Long expire = tokenStoreCache.getExpire(accessToken);
if (expire == null) {
return;
}
// 设置用户权限信息
sysUserDetailsService.getUserDetails(user);
// 更新缓存
tokenStoreCache.saveUser(accessToken, user, expire);
}
}

View File

@ -0,0 +1,33 @@
package net.maku.system.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import net.maku.framework.common.utils.DateUtils;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* AccessToken
*
* @author 阿沐 babamu@126.com
* <a href="https://maku.net">MAKU</a>
*/
@Data
@Schema(description = "AccessToken")
public class AccessTokenVO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Schema(description = "access_token")
@JsonProperty(value = "access_token")
private String accessToken;
@Schema(description = "access_token 过期时间")
@JsonFormat(pattern = DateUtils.DATE_TIME_PATTERN)
private Date accessTokenExpire;
}

View File

@ -0,0 +1,40 @@
package net.maku.system.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import net.maku.framework.common.utils.DateUtils;
import java.io.Serializable;
import java.util.Date;
/**
* 用户Token
*
* @author 阿沐 babamu@126.com
* <a href="https://maku.net">MAKU</a>
*/
@Data
@AllArgsConstructor
@Schema(description = "用户Token")
public class SysUserTokenVO implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description = "access_token")
@JsonProperty(value = "access_token")
private String accessToken;
@Schema(description = "refresh_token")
@JsonProperty(value = "refresh_token")
private String refreshToken;
@Schema(description = "access_token 过期时间")
@JsonFormat(pattern = DateUtils.DATE_TIME_PATTERN)
private Date accessTokenExpire;
@Schema(description = "refresh_token 过期时间")
@JsonFormat(pattern = DateUtils.DATE_TIME_PATTERN)
private Date refreshTokenExpire;
}

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="net.maku.system.dao.SysUserTokenDao">
<select id="getOnlineAccessTokenListByRoleId" resultType="string">
select t3.access_token from sys_role t1, sys_user_role t2, sys_user_token t3
where t1.id = t2.role_id and t2.user_id = t3.user_id and
t1.id = #{roleId} and t3.access_token_expire >= #{time}
</select>
<select id="getOnlineAccessTokenListByUserId" resultType="string">
select access_token from sys_user_token where user_id = #{userId} and access_token_expire >= #{time}
</select>
</mapper>