oauth-重写-简化合并组件

This commit is contained in:
2025-09-21 19:03:05 +08:00
parent 5ad43fd617
commit a8aa415858
18 changed files with 290 additions and 746 deletions

View File

@@ -1,120 +0,0 @@
package com.accompany.core.util;
import com.accompany.common.config.WebSecurityConfig;
import com.accompany.core.model.Account;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* Created by yuanyi on 2019/2/21.
*/
@Component
public class JwtUtils {
/**
* 用户登录成功后生成Jwt
* 使用Hs256算法 私匙使用用户密码
* @param ttlMillis jwt过期时间
* @return
*/
public String createJWT(Long ttlMillis, Long uid) {
//指定签名的时候使用的签名算法也就是header那部分jjwt已经将这部分内容封装好了。
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
//生成JWT的时间
long nowMillis = System.currentTimeMillis();
Date now = new Date(nowMillis);
//创建payload的私有声明根据特定的业务需要添加如果要拿这个做验证一般是需要和jwt的接收方提前沟通好验证方式的
Map<String, Object> claims = new HashMap<String, Object>();
claims.put("uid", uid);
//生成签名的时候使用的秘钥secret,这个方法本地封装了的一般可以从本地配置文件中读取切记这个秘钥不能外露哦。它就是你服务端的私钥在任何场景都不应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。
// String key = PropertyUtil.getProperty("jwtH5Key");
String key = WebSecurityConfig.jwtWebKey;
//生成签发人,这里以平台号为签发人
String subject = uid.toString();
//下面就是在为payload添加各种标准声明和私有声明了
//这里其实就是new一个JwtBuilder设置jwt的body
JwtBuilder builder = Jwts.builder()
//如果有私有声明一定要先设置这个自己创建的私有的声明这个是给builder的claim赋值一旦写在标准的声明赋值之后就是覆盖了那些标准的声明的
.setClaims(claims)
//设置jti(JWT ID)是JWT的唯一标识根据业务需要这个可以设置为一个不重复的值主要用来作为一次性token,从而回避重放攻击。
.setId(UUID.randomUUID().toString())
//iat: jwt的签发时间
.setIssuedAt(now)
//代表这个JWT的主体即它的所有人这个是一个json格式的字符串可以存放什么useridroldid之类的作为什么用户的唯一标志。
.setSubject(subject)
//设置签名使用的签名算法和签名使用的秘钥
.signWith(signatureAlgorithm, key);
if (ttlMillis >= 0) {
long expMillis = nowMillis + ttlMillis;
Date exp = new Date(expMillis);
//设置过期时间
builder.setExpiration(exp);
}
return builder.compact();
}
/**
* Token的解密
* @param token 加密后的token
* @return
*/
public Claims parseJWT(String token) {
//签名秘钥,和生成的签名的秘钥一模一样
String key = WebSecurityConfig.jwtWebKey;
//得到DefaultJwtParser
Claims claims = Jwts.parser()
//设置签名的秘钥
.setSigningKey(key)
//设置需要解析的jwt
.build()
.parseClaimsJws(token)
.getBody();
return claims;
}
/**
* 校验token
* 在这里可以使用官方的校验我这里校验的是token中携带的密码于数据库一致的话就校验通过
* @param token
* @return
*/
public Boolean isVerify(String token, Account account) {
//签名秘钥,和生成的签名的秘钥一模一样
String key = WebSecurityConfig.jwtWebKey;
//得到DefaultJwtParser
Claims claims = Jwts.parser()
//设置签名的秘钥
.setSigningKey(key)
//设置需要解析的jwt
.build()
.parseClaimsJws(token)
.getBody();
if (claims.get("password").equals(account.getPassword())) {
return true;
}
return false;
}
}

View File

@@ -1,49 +0,0 @@
package com.accompany.oauth.constant;
/**
* 用户状态枚举
*
* @author Accompany OAuth Team
* @since 1.0.0
*/
public enum UserStatus {
/**
* 正常状态
*/
NORMAL(1, "正常"),
/**
* 已冻结
*/
FROZEN(2, "已冻结"),
/**
* 已删除
*/
DELETED(3, "已删除");
private final int code;
private final String description;
UserStatus(int code, String description) {
this.code = code;
this.description = description;
}
public int getCode() {
return code;
}
public String getDescription() {
return description;
}
public static UserStatus fromCode(int code) {
for (UserStatus status : values()) {
if (status.code == code) {
return status;
}
}
throw new IllegalArgumentException("未知的用户状态: " + code);
}
}

View File

@@ -1,112 +0,0 @@
package com.accompany.oauth.dto;
import com.accompany.oauth.constant.GrantTypeEnum;
import com.accompany.common.device.DeviceInfo;
/**
* 认证凭据DTO
*
* @author Accompany OAuth Team
* @since 1.0.0
*/
public class AuthCredentials {
/**
* 认证类型
*/
private GrantTypeEnum type;
/**
* 主体标识(手机号/邮箱/OpenID等)
*/
private String principal;
/**
* 凭据(密码/验证码等)
*/
private String credentials;
/**
* 客户端ID
*/
private String clientId;
/**
* 设备信息
*/
private DeviceInfo deviceInfo;
/**
* 权限范围
*/
private String scope;
public AuthCredentials() {
}
public AuthCredentials(GrantTypeEnum type, String principal, String credentials) {
this.type = type;
this.principal = principal;
this.credentials = credentials;
}
public GrantTypeEnum getType() {
return type;
}
public void setType(GrantTypeEnum type) {
this.type = type;
}
public String getPrincipal() {
return principal;
}
public void setPrincipal(String principal) {
this.principal = principal;
}
public String getCredentials() {
return credentials;
}
public void setCredentials(String credentials) {
this.credentials = credentials;
}
public String getClientId() {
return clientId;
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
public DeviceInfo getDeviceInfo() {
return deviceInfo;
}
public void setDeviceInfo(DeviceInfo deviceInfo) {
this.deviceInfo = deviceInfo;
}
public String getScope() {
return scope;
}
public void setScope(String scope) {
this.scope = scope;
}
@Override
public String toString() {
return "AuthCredentials{" +
"type=" + type +
", principal='" + principal + '\'' +
", credentials='[PROTECTED]'" +
", clientId='" + clientId + '\'' +
", deviceInfo=" + deviceInfo +
", scope='" + scope + '\'' +
'}';
}
}

View File

@@ -1,59 +0,0 @@
package com.accompany.oauth.dto;
import lombok.Data;
/**
* OAuth Token请求DTO
*
* @author Accompany OAuth Team
* @since 1.0.0
*/
@Data
public class TokenRequest {
/**
* 授权类型 (password, verify_code, email, openid, refresh_token)
*/
private String grantType;
/**
* 用户名/手机号/邮箱/OpenID
*/
private String username;
/**
* 密码/验证码
*/
private String password;
/**
* 验证码 (兼容OAuth2)
*/
private String code;
/**
* 客户端ID
*/
private String clientId;
/**
* 客户端密钥
*/
private String clientSecret;
/**
* 刷新令牌(当grant_type为refresh_token时使用)
*/
private String refreshToken;
/**
* 第三方登录类型(Apple/微信等)
*/
private String thirdType;
/**
* 设备ID
*/
private String deviceId;
}

View File

@@ -1,68 +1,99 @@
package com.accompany.oauth.ticket;
import java.util.Date;
import java.util.Map;
import java.util.Set;
import java.io.Serializable;
import java.util.*;
/**
* Ticket接口 - OAuth访问票据
* 迁移自OAuth2模块的Ticket接口
* Ticket - OAuth访问票据
* 合并了接口和默认实现的功能
*
* @author Accompany OAuth Team
* @since 1.0.0
*/
public interface Ticket {
public class Ticket implements Serializable {
public static final String ONCE_TYPE = "once";
public static final String MULTI_TYPE = "multi";
String ONCE_TYPE = "once";
String MULTI_TYPE = "multi";
private String value;
private Date expiration;
private String ticketType = ONCE_TYPE.toLowerCase();
private String accessToken;
private Set<String> scope;
private Map<String, Object> additionalInformation = Collections.emptyMap();
/**
* 获取附加信息
*
* @return 附加信息Map
* 创建票据
*/
Map<String, Object> getAdditionalInformation();
public Ticket(String value) {
this.value = value;
}
/**
* 获取关联的访问令牌
*
* @return 访问令牌值
* 复制构造函数
*/
String getAccessToken();
public Ticket(Ticket ticket) {
this(ticket.getValue());
setAdditionalInformation(ticket.getAdditionalInformation());
setAccessToken(ticket.getAccessToken());
setExpiration(ticket.getExpiration());
setScope(ticket.getScope());
setTicketType(ticket.getTicketType());
}
/**
* 获取票据类型
*
* @return 票据类型
*/
String getTicketType();
public void setAdditionalInformation(Map<String, Object> additionalInformation) {
this.additionalInformation = new LinkedHashMap<>(additionalInformation);
}
/**
* 获取过期时间
*
* @return 过期时间
*/
Date getExpiration();
public Map<String, Object> getAdditionalInformation() {
return additionalInformation;
}
/**
* 获取过期时间(秒)
*
* @return 过期秒数
*/
int getExpiresIn();
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
/**
* 获取票据值
*
* @return 票据值
*/
String getValue();
public String getAccessToken() {
return accessToken;
}
/**
* 获取权限范围
*
* @return 权限范围Set
*/
Set<String> getScope();
public void setTicketType(String ticketType) {
this.ticketType = ticketType;
}
public String getTicketType() {
return ticketType;
}
public void setExpiration(Date expiration) {
this.expiration = expiration;
}
public Date getExpiration() {
return expiration;
}
public void setExpiresIn(int delta) {
setExpiration(new Date(System.currentTimeMillis() + delta * 1000L));
}
public int getExpiresIn() {
return expiration != null ? Long.valueOf((expiration.getTime() - System.currentTimeMillis()) / 1000L)
.intValue() : 0;
}
public String getValue() {
return this.value;
}
public void setValue(String value) {
this.value = value;
}
public void setScope(Set<String> scope) {
this.scope = scope;
}
public Set<String> getScope() {
return scope;
}
}

View File

@@ -4,11 +4,9 @@ import com.accompany.common.constant.Constant;
import com.accompany.common.device.DeviceInfo;
import com.accompany.common.redis.RedisKey;
import com.accompany.common.status.BusiStatus;
import com.accompany.common.utils.CommonUtil;
import com.accompany.core.exception.ServiceException;
import com.accompany.core.model.Account;
import com.accompany.core.model.AccountLoginRecord;
import com.accompany.core.model.PrettyNumberRecord;
import com.accompany.core.model.Users;
import com.accompany.core.mybatismapper.PrettyNumberRecordMapper;
import com.accompany.core.service.SysConfService;
@@ -22,8 +20,6 @@ import com.accompany.core.service.user.UsersBaseService;
import com.accompany.email.service.EmailService;
import com.accompany.oauth.constant.LoginTypeEnum;
import com.accompany.sms.service.SmsService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -35,7 +31,7 @@ import java.util.List;
@Slf4j
@Service
public class MyUserDetailsService {
public class AccountLoginService {
@Autowired
private JedisService jedisService;
@@ -59,8 +55,6 @@ public class MyUserDetailsService {
private SysConfService sysConfService;
@Autowired
private RegionNetworkService regionService;
@Autowired
private PrettyNumberRecordMapper prettyNumberRecordMapper;
/**
* 不允许登录的用户账号类型

View File

@@ -5,7 +5,7 @@ import com.accompany.oauth.constant.GrantTypeEnum;
import com.accompany.oauth.constant.LoginTypeEnum;
import com.accompany.oauth.dto.AuthResult;
import com.accompany.oauth.exception.AuthenticationException;
import com.accompany.oauth.manager.TokenManager;
import com.accompany.oauth.token.TokenManager;
import com.accompany.oauth.model.TokenPair;
import com.accompany.common.device.DeviceInfo;
import org.springframework.beans.factory.annotation.Autowired;
@@ -23,7 +23,7 @@ public class AuthenticationService {
@Autowired
private UserService userService;
@Autowired
private MyUserDetailsService myUserDetailsService;
private AccountLoginService accountLoginService;
@Autowired
private TokenManager tokenManager;
@@ -67,7 +67,7 @@ public class AuthenticationService {
// 2. 检查用户状态
userService.checkUserStatus(account);
myUserDetailsService.login(account, loginTypeEnum, deviceInfo, null);
accountLoginService.login(account, loginTypeEnum, deviceInfo, null);
// 3. 生成Token
TokenPair tokenPair = tokenManager.generateToken(account.getUid());

View File

@@ -10,15 +10,11 @@ import com.accompany.core.model.Account;
import com.accompany.core.util.KeyStore;
import com.accompany.core.util.MD5;
import com.accompany.oauth.constant.LoginTypeEnum;
import com.accompany.oauth.constant.UserStatus;
import com.accompany.oauth.exception.AuthenticationException;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.HashSet;
/**
* 用户服务 - 用户认证和信息查询
*
@@ -31,7 +27,7 @@ public class UserService {
@Autowired
private AccountManageService accountManageService;
@Autowired
private MyUserDetailsService myUserDetailsService;
private AccountLoginService accountLoginService;
/**
* 通过密码认证用户
@@ -54,7 +50,7 @@ public class UserService {
// BusiStatus.USER_NOT_EXISTED.getReasonPhrase());
}
myUserDetailsService.validPwd(username, password, account.getPassword());
accountLoginService.validPwd(username, password, account.getPassword());
return account;
}
@@ -67,7 +63,7 @@ public class UserService {
Account account = accountManageService.getOrGenAccountByPhone(phone, phoneAreaCode, code, deviceInfo);
//校验验证码
myUserDetailsService.checkCodeByUserType(account, code, LoginTypeEnum.PHONE);
accountLoginService.checkCodeByUserType(account, code, LoginTypeEnum.PHONE);
return account;
}
@@ -85,7 +81,7 @@ public class UserService {
Account account = accountManageService.getOrGenAccountByEmail(email, code, deviceInfo, deviceInfo.getClientIp());
//校验验证码
myUserDetailsService.checkCodeByUserType(account, code, LoginTypeEnum.EMAIL);
accountLoginService.checkCodeByUserType(account, code, LoginTypeEnum.EMAIL);
return account;
}

View File

@@ -1,104 +0,0 @@
package com.accompany.oauth.ticket;
import java.io.Serializable;
import java.util.*;
/**
* 默认Ticket实现
* 迁移自OAuth2模块的DefaultTicket
*
* @author Accompany OAuth Team
* @since 1.0.0
*/
public class DefaultTicket implements Ticket, Serializable {
private String value;
private Date expiration;
private String ticketType = ONCE_TYPE.toLowerCase();
private String accessToken;
private Set<String> scope;
private Map<String, Object> additionalInformation = Collections.emptyMap();
/**
* 创建票据
*/
public DefaultTicket(String value) {
this.value = value;
}
/**
* 复制构造函数
*/
public DefaultTicket(Ticket ticket) {
this(ticket.getValue());
setAdditionalInformation(ticket.getAdditionalInformation());
setAccessToken(ticket.getAccessToken());
setExpiration(ticket.getExpiration());
setScope(ticket.getScope());
setTicketType(ticket.getTicketType());
}
public void setAdditionalInformation(Map<String, Object> additionalInformation) {
this.additionalInformation = new LinkedHashMap<>(additionalInformation);
}
@Override
public Map<String, Object> getAdditionalInformation() {
return additionalInformation;
}
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
@Override
public String getAccessToken() {
return accessToken;
}
public void setTicketType(String ticketType) {
this.ticketType = ticketType;
}
@Override
public String getTicketType() {
return ticketType;
}
public void setExpiration(Date expiration) {
this.expiration = expiration;
}
@Override
public Date getExpiration() {
return expiration;
}
@Override
public int getExpiresIn() {
return expiration != null ? Long.valueOf((expiration.getTime() - System.currentTimeMillis()) / 1000L)
.intValue() : 0;
}
@Override
public String getValue() {
return this.value;
}
public void setValue(String value) {
this.value = value;
}
public void setScope(Set<String> scope) {
this.scope = scope;
}
@Override
public Set<String> getScope() {
return scope;
}
}

View File

@@ -1,83 +0,0 @@
package com.accompany.oauth.ticket;
import com.accompany.core.model.Account;
import com.accompany.oauth.config.OAuthConfig;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* JWT票据增强器
* 迁移自OAuth2模块的JwtTicketConverter
*
* @author Accompany OAuth Team
* @since 1.0.0
*/
@Component
public class TicketEnhancer {
@Autowired
private OAuthConfig oAuthConfig;
public Ticket enhance(Ticket ticket, Account account) {
DefaultTicket result = new DefaultTicket(ticket);
result.setValue(encode(ticket, account));
return result;
}
/**
* 编码票据为JWT
*
* @param ticket 票据
* @param account
* @return JWT字符串
*/
protected String encode(Ticket ticket, Account account) {
try {
Map<String, Object> claims = convertTicket(ticket, account);
SecretKeySpec secretKey = new SecretKeySpec(oAuthConfig.getJwtSignKey().getBytes(StandardCharsets.UTF_8), SignatureAlgorithm.HS256.getJcaName());
Date now = new Date();
Date expiration = ticket.getExpiration();
JwtBuilder builder = Jwts.builder()
.setClaims(claims)
.setIssuedAt(now)
.setExpiration(expiration)
.signWith(secretKey, SignatureAlgorithm.HS256);
return builder.compact();
} catch (Exception e) {
throw new IllegalStateException("Cannot convert ticket to JWT", e);
}
}
/**
* 转换票据为Claims
*
* @param ticket 票据
* @param account
* @return Claims Map
*/
protected Map<String, Object> convertTicket(Ticket ticket, Account account) {
Map<String, Object> response = new HashMap<>();
response.put("ticket_id", ticket.getValue());
response.put("client_id", oAuthConfig.getClientId());
response.put("exp", ticket.getExpiresIn());
response.put("uid", account.getUid());
response.put("ticket_type", ticket.getTicketType());
response.put("scope", "read write");
return response;
}
}

View File

@@ -10,10 +10,11 @@ import com.accompany.core.service.account.UserAppService;
import com.accompany.oauth.constant.LoginTypeEnum;
import com.accompany.oauth.dto.TicketResponseVO;
import com.accompany.oauth.exception.TokenException;
import com.accompany.oauth.manager.TokenManager;
import com.accompany.oauth.token.TokenManager;
import com.accompany.oauth.model.TokenValidation;
import com.accompany.oauth.service.MyUserDetailsService;
import com.accompany.oauth.service.AccountLoginService;
import com.accompany.oauth.service.UserService;
import com.accompany.oauth.util.JwtUtil;
import org.redisson.api.RMapCache;
import org.redisson.api.RedissonClient;
import org.redisson.client.codec.StringCodec;
@@ -39,14 +40,14 @@ public class TicketService implements InitializingBean {
@Autowired
private UserService userService;
@Autowired
private TicketEnhancer ticketEnhancer;
private JwtUtil jwtUtil;
@Autowired
private UserAppService userAppService;
@Autowired
private MyUserDetailsService myUserDetailsService;
private AccountLoginService accountLoginService;
@Autowired
private LoginRecordService loginRecordService;
@Autowired
@@ -76,24 +77,25 @@ public class TicketService implements InitializingBean {
Date expiration = validation.getExpirationTime();
// 4. 创建票据
DefaultTicket defaultTicket = new DefaultTicket(UUID.randomUUID().toString());
defaultTicket.setAccessToken(accessToken);
defaultTicket.setExpiration(expiration);
defaultTicket.setTicketType(Ticket.MULTI_TYPE);
defaultTicket.setScope(validation.getScopes());
Ticket ticket = new Ticket(UUID.randomUUID().toString());
ticket.setAccessToken(accessToken);
ticket.setExpiration(expiration);
ticket.setTicketType(Ticket.MULTI_TYPE);
ticket.setScope(validation.getScopes());
// 5. 增强票据(JWT签名)
Ticket enhancedTicket = ticketEnhancer.enhance(defaultTicket, account);
String ticketValue = jwtUtil.generateTicket(ticket, account.getUid());
ticket.setValue(ticketValue);
// 6. 存储票据
ticketCache.fastPut(account.getUid(), enhancedTicket.getValue(), defaultTicket.getExpiresIn(), TimeUnit.SECONDS);
ticketCache.fastPut(account.getUid(), ticketValue, ticket.getExpiresIn(), TimeUnit.SECONDS);
// 7. 构建响应
TicketResponseVO response = new TicketResponseVO();
response.setUid(account.getUid());
List<TicketResponseVO.TicketVO> tickets = new ArrayList<>();
tickets.add(createTicketVo(enhancedTicket));
tickets.add(createTicketVo(ticket));
response.setTickets(tickets);
return response;
@@ -111,10 +113,10 @@ public class TicketService implements InitializingBean {
ticketVo.setExpiresIn(ticket.getExpiresIn());
return ticketVo;
}
/**
* 保存登录记录(异步)
*
*
* @param uid 用户ID
* @param ipAddress IP地址
* @param deviceInfo 设备信息
@@ -127,7 +129,7 @@ public class TicketService implements InitializingBean {
if (count <= 0L) {
Account account = accountService.getAccountByUid(id);
Optional.ofNullable(account).ifPresent(acc -> {
AccountLoginRecord record = myUserDetailsService.buildAccountLoginRecord(ipAddress, acc, LoginTypeEnum.TICKET.getValue(), deviceInfo, null);
AccountLoginRecord record = accountLoginService.buildAccountLoginRecord(ipAddress, acc, LoginTypeEnum.TICKET.getValue(), deviceInfo, null);
loginRecordService.addAccountLoginRecord(record);
});
}

View File

@@ -1,4 +1,4 @@
package com.accompany.oauth.manager;
package com.accompany.oauth.token;
import com.accompany.common.redis.RedisKey;
import com.accompany.core.util.StringUtils;

View File

@@ -3,6 +3,7 @@ package com.accompany.oauth.util;
import com.accompany.common.utils.UUIDUtil;
import com.accompany.oauth.config.OAuthConfig;
import com.accompany.oauth.exception.TokenException;
import com.accompany.oauth.ticket.Ticket;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import lombok.Getter;
@@ -13,6 +14,8 @@ import org.springframework.stereotype.Component;
import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* JWT工具类 - 使用更安全的实现
@@ -82,7 +85,28 @@ public class JwtUtil implements InitializingBean {
.signWith(secretKey, SignatureAlgorithm.HS256)
.compact();
}
public String generateTicket(Ticket ticket, Long uid){
Map<String, Object> claims = new HashMap<>();
claims.put("ticket_id", ticket.getValue());
claims.put("client_id", oAuthConfig.getClientId());
claims.put("exp", ticket.getExpiresIn());
claims.put("uid", uid);
claims.put("ticket_type", ticket.getTicketType());
claims.put("scope", "read write");
Date now = new Date();
Date expiration = ticket.getExpiration();
JwtBuilder builder = Jwts.builder()
.setClaims(claims)
.setIssuedAt(now)
.setExpiration(expiration)
.signWith(secretKey, SignatureAlgorithm.HS256);
return builder.compact();
}
/**
* 验证并解析JWT令牌
*
@@ -103,7 +127,7 @@ public class JwtUtil implements InitializingBean {
throw TokenException.invalidToken();
}
}
/**
* 生成JWT Token ID (兼容OAuth2)
*

View File

@@ -1,28 +0,0 @@
spring:
# Redis配置 - 开发环境
redis:
redisson:
config: |
singleServerConfig:
address: "redis://127.0.0.1:6379"
password: null
database: 1
connectionPoolSize: 5
connectionMinimumIdleSize: 1
connectTimeout: 3000
timeout: 3000
# OAuth配置 - 开发环境
oauth:
jwt:
secret: accompany-oauth-dev-secret-key-2024
access-token-expiration: 3600 # 开发环境1小时
refresh-token-expiration: 604800 # 开发环境7天
# 日志配置 - 开发环境
logging:
level:
com.accompany.oauth: DEBUG
org.springframework.web: DEBUG
org.redisson: DEBUG
io.jsonwebtoken: DEBUG

View File

@@ -0,0 +1,74 @@
#MySQL数据库配置
spring:
dynamic-datasource:
master:
poolName: master
jdbcUrl: jdbc:mysql://124.156.164.187:3306/peko?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&tinyInt1isBit=false&useSSL=false&useCursorFetch=true
username: root
password: anan@dev##
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.zaxxer.hikari.HikariDataSource
hikari:
minimum-idle: 10
maximum-pool-size: 20
connection-test-query: select 1
max-lifetime: 7000
slave:
poolName: slave
jdbcUrl: jdbc:mysql://124.156.164.187:3306/peko?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&tinyInt1isBit=false&useSSL=false&useCursorFetch=true
username: root
password: anan@dev##
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.zaxxer.hikari.HikariDataSource
hikari:
minimum-idle: 10
maximum-pool-size: 20
connection-test-query: select 1
max-lifetime: 7000
redis:
host: 124.156.164.187
port: 6200
maxTotal: 100
maxIdle: 50
maxWait: 2500
testOnBorrow: true
testOnReturn: true
password: anan@dev@redis@#!
redisson:
# file: classpath:redisson.yaml
config: |
singleServerConfig:
address: redis://124.156.164.187:6200
password: anan@dev@redis@#!
connectionMinimumIdleSize: 4
timeout: 10000
threads: 8
nettyThreads: 16
codec: !<org.redisson.codec.JsonJacksonCodec> {}
transportMode: "NIO"
## rocketmq 配置
rocketmq:
name-server: 124.156.164.187:9876
producer:
group: peko-group
sendMessageTimeout: 300000
server:
port: 8081
oauth2:
server:
clientId: erban-client
clientSecret: uyzjdhds
jwtSignKey: dh293Hkdjf3G
yidunSecretId: 53ac2fc2d00e3ffc4eafbfe6305aed03
yidunSecretKey: 0b9cd0854bc6be2e5d709cc967f3fc38
registerBusinessId: af43d0f8752147c48f8281800da6049e
registerSwitch: false
registerApiUrl: https://ac.dun.163yun.com/v2/register/check
loginBusinessId: 67881c7a69764c058435ba93a51b1285
loginSwitch: false
logiApiUrl: https://ac.dun.163yun.com/v2/login/check
registerOpened: false
loginOpened: false

View File

@@ -1,30 +0,0 @@
spring:
# Redis配置 - 生产环境
redis:
redisson:
config: |
singleServerConfig:
address: "redis://${REDIS_HOST:127.0.0.1}:${REDIS_PORT:6379}"
password: ${REDIS_PASSWORD:null}
database: ${REDIS_DATABASE:0}
connectionPoolSize: 20
connectionMinimumIdleSize: 5
connectTimeout: 5000
timeout: 5000
retryAttempts: 3
retryInterval: 2000
# OAuth配置 - 生产环境
oauth:
jwt:
secret: ${JWT_SECRET:accompany-oauth-prod-secret-key-2024-very-secure}
access-token-expiration: ${ACCESS_TOKEN_EXPIRATION:7200}
refresh-token-expiration: ${REFRESH_TOKEN_EXPIRATION:2592000}
# 日志配置 - 生产环境
logging:
level:
com.accompany.oauth: INFO
org.springframework.web: WARN
org.redisson: WARN
root: WARN

View File

@@ -1,75 +0,0 @@
server:
port: 8081
servlet:
context-path: /
spring:
application:
name: accompany-oauth
profiles:
active: dev
# Redis配置 (Redisson)
redis:
redisson:
config: |
singleServerConfig:
address: "redis://127.0.0.1:6379"
password: null
database: 0
connectionPoolSize: 10
connectionMinimumIdleSize: 2
connectTimeout: 3000
timeout: 3000
retryAttempts: 3
retryInterval: 1500
# OAuth配置
oauth:
jwt:
secret: accompany-oauth-secret-key-for-jwt-token-generation-2024
access-token-expiration: 7200 # 访问令牌有效期(秒) - 2小时
refresh-token-expiration: 2592000 # 刷新令牌有效期(秒) - 30天
client:
default:
client-id: default
client-secret: default-secret
grant-types: password,verify_code,email,openid,refresh_token
scopes: read,write
access-token-validity: 7200
refresh-token-validity: 2592000
# 日志配置
logging:
level:
com.accompany.oauth: DEBUG
org.springframework.web: INFO
org.redisson: INFO
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
file: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
file:
name: logs/accompany-oauth.log
max-size: 100MB
max-history: 30
# 管理端点配置
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
endpoint:
health:
show-details: when_authorized
server:
port: 8082
# Swagger文档配置
springdoc:
api-docs:
path: /v3/api-docs
swagger-ui:
path: /swagger-ui.html
operationsSorter: method

View File

@@ -0,0 +1,83 @@
spring:
application:
name: oauth
profiles:
active: native
main:
allow-bean-definition-overriding : true
allow-circular-references: true
mvc:
pathmatch:
matching-strategy: ant_path_matcher
---
spring:
config:
activate:
on-profile: native
cloud:
nacos:
config:
server-addr: 124.156.164.187:8848
namespace: 5edc3246-3e69-4be5-a32a-273f0a09ddf6
file-extension: yml
shared-configs:
- data-id: application.yml
refresh: true
- data-id: thirdpart.yml
refresh: true
- data-id: pay.yml
refresh: true
- data-id: sysconf.yml
refresh: true
- data-id: dtp.yml
refresh: true
---
spring:
config:
activate:
on-profile: dev
cloud:
nacos:
config:
server-addr: 124.156.164.187:8848
namespace: 5edc3246-3e69-4be5-a32a-273f0a09ddf6
file-extension: yml
shared-configs:
- data-id: application.yml
refresh: true
- data-id: thirdpart.yml
refresh: true
- data-id: pay.yml
refresh: true
- data-id: sysconf.yml
refresh: true
- data-id: dtp.yml
refresh: true
- data-id: database.yml
refresh: true
---
spring:
config:
activate:
on-profile: prod
cloud:
nacos:
config:
server-addr: 172.19.16.15:8848
namespace: 0c9bf047-19ca-4969-bf5d-bbc1f86b501a
file-extension: yml
shared-configs:
- data-id: application.yml
refresh: true
- data-id: thirdpart.yml
refresh: true
- data-id: pay.yml
refresh: true
- data-id: sysconf.yml
refresh: true
- data-id: threadpool.yml
refresh: true
- data-id: database.yml
refresh: true