初始化

This commit is contained in:
2022-06-21 20:47:46 +08:00
parent b666a24a98
commit 59da3376c1
1246 changed files with 129600 additions and 0 deletions

View File

@@ -0,0 +1,47 @@
package com.njcn.auth.service;
import cn.hutool.core.bean.BeanUtil;
import com.njcn.auth.pojo.bo.BusinessUser;
import com.njcn.common.pojo.response.HttpResult;
import com.njcn.common.utils.LogUtil;
import com.njcn.user.api.UserFeignClient;
import com.njcn.user.pojo.dto.UserDTO;
import com.njcn.web.utils.RequestUtil;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
/**
* @author hongawen
* <p>
* 自定义用户认证和授权
*/
@Slf4j
@Service
@AllArgsConstructor
public class UserDetailsServiceImpl implements UserDetailsService {
private final UserFeignClient userFeignClient;
@SneakyThrows
@Override
public UserDetails loadUserByUsername(String loginName) throws UsernameNotFoundException {
String clientId = RequestUtil.getOAuth2ClientId();
BusinessUser businessUser = new BusinessUser(loginName, null, null);
businessUser.setClientId(clientId);
HttpResult<UserDTO> result = userFeignClient.getUserByName(loginName);
LogUtil.njcnDebug(log, "用户认证时,用户名:{}获取用户信息:{}", loginName, result.toString());
//成功获取用户信息
UserDTO userDTO = result.getData();
BeanUtil.copyProperties(userDTO,businessUser,true);
businessUser.setAuthorities(AuthorityUtils.commaSeparatedStringToAuthorityList(String.join(",", userDTO.getRoleName())));
return businessUser;
}
}

View File

@@ -0,0 +1,121 @@
package com.njcn.auth.service;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.nimbusds.jose.JWSObject;
import com.njcn.common.pojo.constant.SecurityConstants;
import com.njcn.common.pojo.dto.UserTokenInfo;
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.redis.utils.RedisUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.oauth2.common.OAuth2RefreshToken;
import org.springframework.stereotype.Service;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import java.text.ParseException;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;
/**
* @author hongawen
* @version 1.0.0
* @date 2022年03月11日 10:34
*/
@Slf4j
@Service
@AllArgsConstructor
public class UserTokenService {
private final RedisUtil redisUtil;
/**
* 记录用户token信息并经过处理后达到最新登录的使用者将之前的token信息置为黑名单过期状态
* 1、从在线名单中获取该用户的token信息key为:TOKEN_ONLINE_PREFIX+useridvalue为userTokenInfo的json对象
* 1.1 有,则表示有人使用该账户登录过
* 1.1.1 将在线名单的用户信息添加到黑名单并清除黑名单中已经过期的token信息
* 重新赋值黑名单信息key为TOKEN_BLACKLIST_PREFIX+userid,value为userTokenInfo的集合
* 1.2 没有该账号当前只有本人在登录将当前token等信息保存到白名单
*
* @param oAuth2AccessToken 认证后的最新token信息
*/
@Async("asyncExecutor")
public void recordUserInfo(OAuth2AccessToken oAuth2AccessToken) {
UserTokenInfo userTokenInfo = new UserTokenInfo();
String accessTokenValue = oAuth2AccessToken.getValue();
JWSObject accessJwsObject ;
try {
accessJwsObject = JWSObject.parse(accessTokenValue);
} catch (ParseException e) {
throw new BusinessException(CommonResponseEnum.PARSE_TOKEN_ERROR);
}
JSONObject accessJson = JSONUtil.parseObj(accessJwsObject.getPayload().toString());
String userIndex = accessJson.getStr(SecurityConstants.USER_INDEX_KEY);
//查询是否有在线的当前用户
String onlineUserKey = SecurityConstants.TOKEN_ONLINE_PREFIX + userIndex;
Object onlineTokenInfoOld = redisUtil.getObjectByKey(onlineUserKey);
if (!Objects.isNull(onlineTokenInfoOld)) {
//存在在线用户,将在线用户添加到黑名单列表
String blackUserKey = SecurityConstants.TOKEN_BLACKLIST_PREFIX + userIndex;
List<UserTokenInfo> blackUsers = (List<UserTokenInfo>) redisUtil.getObjectByKey(blackUserKey);
if (CollectionUtils.isEmpty(blackUsers)) {
blackUsers = new ArrayList<>();
}
blackUsers.add((UserTokenInfo) onlineTokenInfoOld);
//筛选黑名单中是否存在过期的token信息
blackUsers.removeIf(userTokenInfoTemp -> userTokenInfoTemp.getRefreshTokenExpire().isBefore(LocalDateTime.now()));
//将黑名单集合重新缓存此处根据最新的黑名单计算当前这个key的生命周期在时间差的基础上增加5分钟的延迟时间
LocalDateTime refreshTokenExpire = ((UserTokenInfo) onlineTokenInfoOld).getRefreshTokenExpire();
long lifeTime = Math.abs(refreshTokenExpire.plusMinutes(5L).toEpochSecond(ZoneOffset.of("+8")) - LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8")));
redisUtil.saveByKeyWithExpire(blackUserKey, blackUsers, lifeTime);
}
String accessJti = accessJson.getStr(SecurityConstants.JWT_JTI);
OAuth2RefreshToken refreshToken = oAuth2AccessToken.getRefreshToken();
JWSObject refreshJwsObject ;
try {
refreshJwsObject = JWSObject.parse(refreshToken.getValue());
} catch (ParseException e) {
throw new BusinessException(CommonResponseEnum.PARSE_TOKEN_ERROR);
}
JSONObject refreshJson = JSONUtil.parseObj(refreshJwsObject.getPayload().toString());
String refreshJti = refreshJson.getStr(SecurityConstants.JWT_JTI);
Long refreshExpireTime = refreshJson.getLong(SecurityConstants.JWT_EXP);
userTokenInfo.setAccessTokenJti(accessJti);
userTokenInfo.setRefreshToken(refreshToken.getValue());
LocalDateTime refreshLifeTime =LocalDateTime.ofEpochSecond(refreshExpireTime,0,ZoneOffset.of("+8"));
userTokenInfo.setRefreshTokenExpire(refreshLifeTime);
//生命周期在refreshToken的基础上延迟5分钟
redisUtil.saveByKeyWithExpire(onlineUserKey, userTokenInfo, refreshLifeTime.plusMinutes(5L).toEpochSecond(ZoneOffset.of("+8")) - LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8")));
}
/**
* 校验刷新token是否被加入黑名单
*
* @param refreshToken 刷新token
*/
public void judgeRefreshToken(String refreshToken) {
JWSObject refreshJwsObject;
try {
refreshJwsObject = JWSObject.parse(refreshToken);
} catch (ParseException e) {
throw new BusinessException();
}
JSONObject refreshJson = JSONUtil.parseObj(refreshJwsObject.getPayload().toString());
String userIndex = refreshJson.getStr(SecurityConstants.USER_INDEX_KEY);
String blackUserKey = SecurityConstants.TOKEN_BLACKLIST_PREFIX + userIndex;
List<UserTokenInfo> blackUsers = (List<UserTokenInfo>) redisUtil.getObjectByKey(blackUserKey);
if (CollectionUtils.isNotEmpty(blackUsers)) {
blackUsers.forEach(temp -> {
//存在当前的刷新token则抛出业务异常
if(temp.getRefreshToken().equalsIgnoreCase(refreshToken)){
throw new BusinessException(CommonResponseEnum.TOKEN_EXPIRE_JWT);
}
});
}
}
}