Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
Y
yd-cloud-core
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
xingmin
yd-cloud-core
Commits
243a95c0
Commit
243a95c0
authored
Sep 01, 2025
by
zhangxingmin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
微服务核心组件配置
parent
de57dff1
Hide whitespace changes
Inline
Side-by-side
Showing
42 changed files
with
1523 additions
and
134 deletions
+1523
-134
.gitignore
+151
-0
yd-auth-core/pom.xml
+26
-0
yd-auth-core/src/main/java/com/yd/auth/core/AuthApplication.java
+1
-1
yd-auth-core/src/main/java/com/yd/auth/core/config/AuthMybatisPlusConfig.java
+44
-0
yd-auth-core/src/main/java/com/yd/auth/core/config/CustomPasswordEncoder.java
+35
-0
yd-auth-core/src/main/java/com/yd/auth/core/config/SecurityConfig.java
+4
-1
yd-auth-core/src/main/java/com/yd/auth/core/dto/AuthUserDto.java
+7
-1
yd-auth-core/src/main/java/com/yd/auth/core/security/JwtAuthenticationFilter.java
+9
-7
yd-auth-core/src/main/java/com/yd/auth/core/security/JwtTokenProvider.java
+158
-50
yd-auth-core/src/main/java/com/yd/auth/core/service/impl/AuthServiceImpl.java
+24
-1
yd-auth-core/src/main/java/com/yd/auth/core/service/impl/AuthUserDetailsService.java
+3
-1
yd-auth-core/src/main/java/com/yd/auth/core/utils/SecurityUtil.java
+28
-0
yd-auth-core/src/main/resources/bootstrap.yml
+1
-0
yd-auth-core/target/maven-archiver/pom.properties
+1
-1
yd-common/pom.xml
+4
-0
yd-common/src/main/java/com/yd/common/constant/ServerNameConstants.java
+14
-0
yd-common/src/main/java/com/yd/common/enums/CommonEnum.java
+20
-1
yd-common/src/main/java/com/yd/common/enums/MenuTypeEnum.java
+31
-0
yd-common/src/main/java/com/yd/common/enums/ResultCode.java
+8
-0
yd-common/src/main/java/com/yd/common/exception/BusinessException.java
+1
-0
yd-common/src/main/java/com/yd/common/utils/Menu.java
+54
-0
yd-common/src/main/java/com/yd/common/utils/RandomStringGenerator.java
+3
-3
yd-common/src/main/java/com/yd/common/utils/SM2Util.java
+63
-0
yd-common/src/main/java/com/yd/common/utils/SM3Util.java
+53
-0
yd-common/src/main/java/com/yd/common/utils/TreeMenuExample.java
+67
-0
yd-common/src/main/java/com/yd/common/utils/TreeUtils.java
+273
-0
yd-common/target/maven-archiver/pom.properties
+1
-1
yd-feign/target/maven-archiver/pom.properties
+1
-1
yd-framework/pom.xml
+4
-0
yd-framework/src/main/java/com/yd/framework/handler/GlobalExceptionHandler.java
+9
-0
yd-framework/target/maven-archiver/pom.properties
+1
-1
yd-gateway/pom.xml
+37
-7
yd-gateway/src/main/java/com/yd/gateway/GatewayApplication.java
+3
-4
yd-gateway/src/main/java/com/yd/gateway/config/CorsConfig.java
+24
-0
yd-gateway/src/main/java/com/yd/gateway/config/GatewayJwtAuthFilterConfig.java
+89
-0
yd-gateway/src/main/java/com/yd/gateway/config/GatewaySecurityConfig.java
+67
-52
yd-gateway/src/main/java/com/yd/gateway/config/RouteDebugFilter.java
+18
-0
yd-gateway/src/main/java/com/yd/gateway/exception/JwtAuthException.java
+14
-0
yd-gateway/src/main/java/com/yd/gateway/utils/JwtTokenUtil.java
+65
-0
yd-gateway/src/main/resources/banner.txt
+13
-0
yd-gateway/src/main/resources/bootstrap.yml
+93
-0
yd-gateway/target/maven-archiver/pom.properties
+1
-1
No files found.
.gitignore
0 → 100644
View file @
243a95c0
### 通用开发环境 ###
# IDE 配置
.idea/
.vscode/
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
# 编辑器临时文件
*~
~$*
*.tmp
*.bak
*.swp
### 操作系统文件 ###
# macOS
.DS_Store
.AppleDouble
.LSOverride
._*
.Spotlight-V100
.Trashes
# Windows
Thumbs.db
ehthumbs.db
[Dd]esktop.ini
$RECYCLE.BIN/
# Linux
.directory
.trash-*
### 编程语言相关 ###
# Java
*.class
*.jar
*.war
*.ear
*.log
target/
build/
out/
bin/
# Python
__pycache__/
*.pyc
*.pyo
*.pyd
*.pyc
env/
venv/
.python-version
# Node.js
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnp/
.pnp.js
# C/C++
*.o
*.ko
*.obj
*.exe
*.dll
*.so
*.dylib
# Rust
/target/
**/*.rs.bk
### 构建系统 ###
# Maven
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
# Gradle
.gradle/
build/
!gradle/wrapper/gradle-wrapper.jar
# Android
*.apk
*.ap_
*.dex
*.class
gen/
bin/
### 日志文件 ###
*.log
logs/
*.logs
### 测试文件 ###
coverage/
.nyc_output/
test-results/
### 系统文件 ###
*.cab
*.msi
*.msix
*.msm
*.msp
### 文档文件 ###
*.pdf
*.doc
*.docx
*.xls
*.xlsx
*.ppt
*.pptx
### 压缩文件 ###
*.zip
*.tar.gz
*.7z
*.rar
*.gz
### 自定义规则 ###
# 项目特定文件
.env
config.local.yml
secrets.ini
# 临时文件
temp/
tmp/
dump.rdb
# 大文件
*.large
*.h5
*.dat
# 排除特定文件
**/pom.properties
**/inputFiles.lst
**/createdFiles.lst
yd-auth-core/pom.xml
View file @
243a95c0
...
...
@@ -19,6 +19,12 @@
<groupId>
com.alibaba.cloud
</groupId>
<artifactId>
spring-cloud-starter-alibaba-nacos-discovery
</artifactId>
</dependency>
<!-- SpringCloud Alibaba Nacos Config -->
<dependency>
<groupId>
com.alibaba.cloud
</groupId>
<artifactId>
spring-cloud-starter-alibaba-nacos-config
</artifactId>
</dependency>
<!-- Spring Boot Starter -->
<dependency>
<groupId>
org.springframework.boot
</groupId>
...
...
@@ -26,6 +32,10 @@
</dependency>
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter
</artifactId>
</dependency>
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-security
</artifactId>
</dependency>
...
...
@@ -64,6 +74,22 @@
<artifactId>
spring-cloud-starter-bootstrap
</artifactId>
</dependency>
<dependency>
<groupId>
com.baomidou
</groupId>
<artifactId>
mybatis-plus-boot-starter
</artifactId>
</dependency>
<dependency>
<groupId>
com.baomidou
</groupId>
<artifactId>
mybatis-plus-generator
</artifactId>
</dependency>
<!-- MyBatis Plus 扩展功能 -->
<dependency>
<groupId>
com.baomidou
</groupId>
<artifactId>
mybatis-plus-extension
</artifactId>
</dependency>
<!-- 阿里数据库连接池 -->
<dependency>
<groupId>
com.alibaba
</groupId>
...
...
yd-auth-core/src/main/java/com/yd/auth/core/AuthApplication.java
View file @
243a95c0
...
...
@@ -7,7 +7,7 @@ import org.springframework.boot.builder.SpringApplicationBuilder;
import
org.springframework.cloud.openfeign.EnableFeignClients
;
@SpringBootApplication
(
scanBasePackages
=
"com.yd"
)
@MapperScan
(
"com.yd.**.
mapper
"
)
@MapperScan
(
"com.yd.**.
dao
"
)
@EnableFeignClients
(
basePackages
=
"com.yd"
)
public
class
AuthApplication
{
...
...
yd-auth-core/src/main/java/com/yd/auth/core/config/AuthMybatisPlusConfig.java
0 → 100644
View file @
243a95c0
package
com
.
yd
.
auth
.
core
.
config
;
import
com.baomidou.mybatisplus.annotation.DbType
;
import
com.baomidou.mybatisplus.core.handlers.MetaObjectHandler
;
import
com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor
;
import
com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor
;
import
org.apache.ibatis.reflection.MetaObject
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
java.time.LocalDateTime
;
@Configuration
public
class
AuthMybatisPlusConfig
{
/**
* 分页插件配置(必须)
*/
@Bean
public
MybatisPlusInterceptor
mybatisPlusInterceptor
()
{
MybatisPlusInterceptor
interceptor
=
new
MybatisPlusInterceptor
();
// 使用正确的枚举值 DbType.MYSQL
interceptor
.
addInnerInterceptor
(
new
PaginationInnerInterceptor
(
DbType
.
MYSQL
));
return
interceptor
;
}
/**
* 自动填充字段配置(如创建时间、更新时间)
*/
@Bean
public
MetaObjectHandler
metaObjectHandler
()
{
return
new
MetaObjectHandler
()
{
@Override
public
void
insertFill
(
MetaObject
metaObject
)
{
this
.
strictInsertFill
(
metaObject
,
"createTime"
,
LocalDateTime
.
class
,
LocalDateTime
.
now
());
}
@Override
public
void
updateFill
(
MetaObject
metaObject
)
{
this
.
strictUpdateFill
(
metaObject
,
"updateTime"
,
LocalDateTime
.
class
,
LocalDateTime
.
now
());
}
};
}
}
yd-auth-core/src/main/java/com/yd/auth/core/config/CustomPasswordEncoder.java
0 → 100644
View file @
243a95c0
package
com
.
yd
.
auth
.
core
.
config
;
import
org.springframework.security.crypto.password.PasswordEncoder
;
import
org.springframework.stereotype.Component
;
/**
* 自定义密码加密器,实现自定义的密码比对逻辑
*/
@Component
public
class
CustomPasswordEncoder
implements
PasswordEncoder
{
/**
* 加密方法:这里简化处理,直接返回原始密码(实际项目中建议加密)
* @param rawPassword 原始密码(用户输入的明文)
* @return 加密后的密码(这里返回明文,仅作示例)
*/
@Override
public
String
encode
(
CharSequence
rawPassword
)
{
// 实际业务中,建议在这里实现你的加密逻辑(如加盐MD5、SHA等)
return
rawPassword
.
toString
();
}
/**
* 密码比对方法:自定义比对逻辑
* @param rawPassword 前端传参的密码(用户输入的明文)
* @param encodedPassword 数据库中存储的密码(可能是加密后的)
* @return 比对结果(true表示一致,false表示不一致)
*/
@Override
public
boolean
matches
(
CharSequence
rawPassword
,
String
encodedPassword
)
{
// 自定义比对逻辑:例如直接比较两个字符串是否相等
// 注意:实际项目中需根据加密规则解密后比对,或加密输入密码后比对
return
rawPassword
.
toString
().
equals
(
encodedPassword
);
}
}
yd-auth-core/src/main/java/com/yd/auth/core/config/SecurityConfig.java
View file @
243a95c0
...
...
@@ -33,9 +33,12 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
this
.
authenticationFilter
=
authenticationFilter
;
}
//密码校验器
@Bean
public
PasswordEncoder
passwordEncoder
()
{
return
new
BCryptPasswordEncoder
();
// return new BCryptPasswordEncoder();
// 返回自定义的加密器实例
return
new
CustomPasswordEncoder
();
}
@Bean
...
...
yd-auth-core/src/main/java/com/yd/auth/core/dto/AuthUserDto.java
View file @
243a95c0
package
com
.
yd
.
auth
.
core
.
dto
;
import
com.baomidou.mybatisplus.annotation.TableField
;
import
lombok.Data
;
import
org.springframework.security.core.GrantedAuthority
;
import
org.springframework.security.core.authority.SimpleGrantedAuthority
;
...
...
@@ -23,7 +24,7 @@ public class AuthUserDto implements UserDetails {
/**
* 用户唯一标识(业务ID),用于业务层面的用户识别
*/
private
String
user
Ui
d
;
private
String
user
BizI
d
;
/**
* 登录账号(实现UserDetails接口必需)
...
...
@@ -35,6 +36,11 @@ public class AuthUserDto implements UserDetails {
*/
private
String
password
;
/**
* 是否超级管理员(0:否 1:是)
*/
private
Integer
isSuperAdmin
;
// ============== Spring Security账户状态属性 ==============
/**
* 账户是否启用(默认true启用)
...
...
yd-auth-core/src/main/java/com/yd/auth/core/security/JwtAuthenticationFilter.java
View file @
243a95c0
...
...
@@ -5,6 +5,7 @@ import com.yd.user.service.model.SysUser;
import
com.yd.user.service.service.ISysUserService
;
import
org.springframework.beans.BeanUtils
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Qualifier
;
import
org.springframework.security.authentication.UsernamePasswordAuthenticationToken
;
import
org.springframework.security.core.context.SecurityContextHolder
;
import
org.springframework.security.core.userdetails.UserDetails
;
...
...
@@ -23,6 +24,7 @@ import java.util.Objects;
public
class
JwtAuthenticationFilter
extends
OncePerRequestFilter
{
@Autowired
@Qualifier
(
"sysUserServiceImpl"
)
private
ISysUserService
iSysUserService
;
private
final
JwtTokenProvider
tokenProvider
;
...
...
@@ -42,10 +44,10 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
// 2. 检查令牌是否存在且有效
if
(
token
!=
null
&&
tokenProvider
.
validateToken
(
token
))
{
// 3. 从JWT令牌中提取用户唯一标识(业务ID)
String
user
Uid
=
tokenProvider
.
getUserUi
dFromToken
(
token
);
String
user
BizId
=
tokenProvider
.
getUserBizI
dFromToken
(
token
);
// 4. 根据用户唯一标识查询用户详细信息(包括权限信息)
UserDetails
userDetails
=
queryUserDetails
(
user
Ui
d
);
UserDetails
userDetails
=
queryUserDetails
(
user
BizI
d
);
// 5. 创建Spring Security认证对象
// - userDetails: 包含用户身份和权限信息
...
...
@@ -64,19 +66,19 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
/**
* 查询用户信息返回spring security认证对象UserDetails
* @param user
Ui
d
* @param user
BizI
d
* @return spring security认证对象UserDetails
*/
public
UserDetails
queryUserDetails
(
String
user
Ui
d
)
{
public
UserDetails
queryUserDetails
(
String
user
BizI
d
)
{
AuthUserDto
authUserDto
=
null
;
SysUser
sysUser
=
iSysUserService
.
queryOne
(
user
Ui
d
);
SysUser
sysUser
=
iSysUserService
.
queryOne
(
user
BizI
d
);
if
(
Objects
.
isNull
(
sysUser
))
{
throw
new
UsernameNotFoundException
(
"用户不存在:"
);
}
authUserDto
=
new
AuthUserDto
();
BeanUtils
.
copyProperties
(
sysUser
,
authUserDto
);
authUserDto
.
setUsername
(
sysUser
.
getUserName
());
// 查询用户角色 TODO
// authUserDto.setRoles(roles);
...
...
@@ -89,6 +91,6 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
if
(
StringUtils
.
hasText
(
bearerToken
)
&&
bearerToken
.
startsWith
(
"Bearer "
))
{
return
bearerToken
.
substring
(
7
);
}
return
null
;
return
bearerToken
;
}
}
yd-auth-core/src/main/java/com/yd/auth/core/security/JwtTokenProvider.java
View file @
243a95c0
package
com
.
yd
.
auth
.
core
.
security
;
import
com.yd.auth.core.dto.AuthUserDto
;
import
io.jsonwebtoken.*
;
import
io.jsonwebtoken.io.Decoders
;
import
io.jsonwebtoken.security.Keys
;
import
io.jsonwebtoken.security.SecurityException
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.security.authentication.UsernamePasswordAuthenticationToken
;
import
org.springframework.security.core.Authentication
;
...
...
@@ -11,83 +14,132 @@ import org.springframework.stereotype.Component;
import
javax.crypto.SecretKey
;
import
java.util.Collection
;
import
java.util.Date
;
import
java.util.Base64
;
import
java.util.Map
;
import
java.util.stream.Collectors
;
/**
* JWT令牌提供者
* 修复了密钥长度不足的问题,并优化了异常处理
*/
@Component
public
class
JwtTokenProvider
{
@Value
(
"${jwt.secret:1}"
)
// 使用512位长度的密钥(通过配置文件设置)
@Value
(
"${jwt.secret}"
)
private
String
jwtSecret
;
@Value
(
"${jwt.expiration
:1}"
)
@Value
(
"${jwt.expiration
}"
)
// 默认24小时(单位毫秒
)
private
int
jwtExpiration
;
/**
* 生成JWT令牌
*/
public
String
generateToken
(
Authentication
authentication
)
{
UserDetails
userDetails
=
(
UserDetails
)
authentication
.
getPrincipal
();
return
Jwts
.
builder
()
.
setSubject
(
userDetails
.
getUsername
())
.
claim
(
"roles"
,
getRoles
(
userDetails
.
getAuthorities
()))
.
setIssuedAt
(
new
Date
())
.
setExpiration
(
new
Date
(
System
.
currentTimeMillis
()
+
jwtExpiration
*
1000L
))
.
signWith
(
getSigningKey
(),
SignatureAlgorithm
.
HS512
)
.
compact
();
if
(
authentication
==
null
||
authentication
.
getPrincipal
()
==
null
)
{
throw
new
JwtAuthenticationException
(
"无法从空认证信息生成令牌"
);
}
AuthUserDto
authUserDto
=
(
AuthUserDto
)
authentication
.
getPrincipal
();
try
{
return
Jwts
.
builder
()
.
setSubject
(
authUserDto
.
getUserBizId
())
.
claim
(
"roles"
,
getRoles
(
authUserDto
.
getAuthorities
()))
.
setIssuedAt
(
new
Date
())
.
setExpiration
(
new
Date
(
System
.
currentTimeMillis
()
+
jwtExpiration
))
.
signWith
(
getSigningKey
(),
SignatureAlgorithm
.
HS512
)
.
compact
();
}
catch
(
Exception
e
)
{
throw
new
JwtAuthenticationException
(
"生成JWT令牌失败: "
+
e
.
getMessage
());
}
}
/**
* 提取角色信息
*/
private
Collection
<
String
>
getRoles
(
Collection
<?
extends
GrantedAuthority
>
authorities
)
{
return
authorities
.
stream
()
.
map
(
GrantedAuthority:
:
getAuthority
)
.
collect
(
Collectors
.
toList
());
}
public
String
getUserUidFromToken
(
String
token
)
{
return
Jwts
.
parserBuilder
()
.
setSigningKey
(
getSigningKey
())
.
build
()
.
parseClaimsJws
(
token
)
.
getBody
()
.
getSubject
();
/**
* 从令牌中获取用户名
*/
public
String
getUsernameFromToken
(
String
token
)
{
try
{
return
Jwts
.
parserBuilder
()
.
setSigningKey
(
getSigningKey
())
.
build
()
.
parseClaimsJws
(
token
)
.
getBody
()
.
getSubject
();
}
catch
(
Exception
e
)
{
throw
new
JwtAuthenticationException
(
"从令牌获取用户名失败: "
+
e
.
getMessage
());
}
}
public
String
getUsernameFromToken
(
String
token
)
{
return
Jwts
.
parserBuilder
()
.
setSigningKey
(
getSigningKey
())
.
build
()
.
parseClaimsJws
(
token
)
.
getBody
()
.
getSubject
();
/**
* 从令牌中获取用户业务id
*/
public
String
getUserBizIdFromToken
(
String
token
)
{
try
{
return
Jwts
.
parserBuilder
()
.
setSigningKey
(
getSigningKey
())
.
build
()
.
parseClaimsJws
(
token
)
.
getBody
()
.
getSubject
();
}
catch
(
Exception
e
)
{
throw
new
JwtAuthenticationException
(
"从令牌获取用户名失败: "
+
e
.
getMessage
());
}
}
/**
* 从令牌中获取认证信息
*/
public
Authentication
getAuthentication
(
String
token
)
{
if
(
validateToken
(
token
))
{
String
username
=
getUsernameFromToken
(
token
);
// 这里应该从数据库加载用户信息,但为了性能通常只加载基本信息
// 实际项目中可以在这里加载用户权限
return
new
UsernamePasswordAuthenticationToken
(
username
,
null
,
// 从token中提取权限
getAuthoritiesFromToken
(
token
)
);
try
{
if
(
validateToken
(
token
))
{
String
username
=
getUsernameFromToken
(
token
);
return
new
UsernamePasswordAuthenticationToken
(
username
,
null
,
getAuthoritiesFromToken
(
token
)
);
}
return
null
;
}
catch
(
Exception
e
)
{
throw
new
JwtAuthenticationException
(
"获取认证信息失败: "
+
e
.
getMessage
());
}
return
null
;
}
/**
* 从令牌中获取权限信息
*/
private
Collection
<?
extends
GrantedAuthority
>
getAuthoritiesFromToken
(
String
token
)
{
Claims
claims
=
Jwts
.
parserBuilder
()
.
setSigningKey
(
getSigningKey
())
.
build
()
.
parseClaimsJws
(
token
)
.
getBody
();
@SuppressWarnings
(
"unchecked"
)
Collection
<
String
>
roles
=
(
Collection
<
String
>)
claims
.
get
(
"roles"
);
return
roles
.
stream
()
.
map
(
role
->
(
GrantedAuthority
)
()
->
role
)
.
collect
(
Collectors
.
toList
());
try
{
Claims
claims
=
Jwts
.
parserBuilder
()
.
setSigningKey
(
getSigningKey
())
.
build
()
.
parseClaimsJws
(
token
)
.
getBody
();
@SuppressWarnings
(
"unchecked"
)
Collection
<
String
>
roles
=
(
Collection
<
String
>)
claims
.
get
(
"roles"
);
return
roles
.
stream
()
.
map
(
role
->
(
GrantedAuthority
)
()
->
role
)
.
collect
(
Collectors
.
toList
());
}
catch
(
Exception
e
)
{
throw
new
JwtAuthenticationException
(
"从令牌获取权限信息失败: "
+
e
.
getMessage
());
}
}
/**
* 验证令牌有效性
*/
public
boolean
validateToken
(
String
token
)
{
try
{
Jwts
.
parserBuilder
().
setSigningKey
(
getSigningKey
()).
build
().
parseClaimsJws
(
token
);
...
...
@@ -101,21 +153,77 @@ public class JwtTokenProvider {
}
catch
(
IllegalArgumentException
e
)
{
throw
new
JwtAuthenticationException
(
"JWT令牌无效"
);
}
catch
(
Exception
e
)
{
throw
new
JwtAuthenticationException
(
"无效的JWT令牌
"
);
throw
new
JwtAuthenticationException
(
"无效的JWT令牌
: "
+
e
.
getMessage
()
);
}
}
/**
* 获取签名密钥
*/
private
SecretKey
getSigningKey
()
{
return
Keys
.
hmacShaKeyFor
(
jwtSecret
.
getBytes
());
try
{
if
(
jwtSecret
==
null
||
jwtSecret
.
trim
().
isEmpty
())
{
throw
new
JwtAuthenticationException
(
"JWT密钥未配置"
);
}
byte
[]
keyBytes
=
Decoders
.
BASE64
.
decode
(
jwtSecret
);
return
Keys
.
hmacShaKeyFor
(
keyBytes
);
}
catch
(
Exception
e
)
{
throw
new
JwtAuthenticationException
(
"获取签名密钥失败: "
+
e
.
getMessage
());
}
}
/**
* 生成符合HS512要求的密钥(用于生成配置文件中的密钥)
*/
public
static
String
generateSecureKey
()
{
try
{
SecretKey
key
=
Keys
.
secretKeyFor
(
SignatureAlgorithm
.
HS512
);
return
Base64
.
getEncoder
().
encodeToString
(
key
.
getEncoded
());
}
catch
(
Exception
e
)
{
throw
new
RuntimeException
(
"生成安全密钥失败"
,
e
);
}
}
public
int
getJwtExpiration
()
{
return
jwtExpiration
;
}
/**
* JWT认证异常
*/
public
static
class
JwtAuthenticationException
extends
RuntimeException
{
public
JwtAuthenticationException
(
String
message
)
{
super
(
message
);
}
public
JwtAuthenticationException
(
String
message
,
Throwable
cause
)
{
super
(
message
,
cause
);
}
}
// 解析 JWT 声明
public
Claims
parseClaims
(
String
token
)
{
return
Jwts
.
parserBuilder
()
.
setSigningKey
(
getSigningKey
())
.
build
()
.
parseClaimsJws
(
token
)
.
getBody
();
}
// 获取 JWT 头部信息
public
Map
<
String
,
Object
>
getHeaders
(
String
token
)
{
return
Jwts
.
parserBuilder
()
.
setSigningKey
(
getSigningKey
())
.
build
()
.
parseClaimsJws
(
token
)
.
getHeader
();
}
public
static
void
main
(
String
[]
args
)
{
// 生成一个符合HS512要求的密钥
System
.
out
.
println
(
"请将以下生成的JWT密钥复制到配置文件中(application.yml或application.properties):"
);
System
.
out
.
println
(
"jwt.secret: "
+
generateSecureKey
());
System
.
out
.
println
(
"jwt.expiration: 86400000 # 24小时"
);
}
}
yd-auth-core/src/main/java/com/yd/auth/core/service/impl/AuthServiceImpl.java
View file @
243a95c0
...
...
@@ -4,16 +4,27 @@ import com.yd.auth.core.request.LoginRequest;
import
com.yd.auth.core.response.LoginResponse
;
import
com.yd.auth.core.security.JwtTokenProvider
;
import
com.yd.auth.core.service.AuthService
;
import
com.yd.common.utils.SM3Util
;
import
com.yd.user.service.model.SysUser
;
import
com.yd.user.service.service.ISysUserService
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Qualifier
;
import
org.springframework.security.authentication.AuthenticationManager
;
import
org.springframework.security.authentication.UsernamePasswordAuthenticationToken
;
import
org.springframework.security.core.Authentication
;
import
org.springframework.security.core.context.SecurityContextHolder
;
import
org.springframework.security.core.userdetails.UsernameNotFoundException
;
import
org.springframework.stereotype.Service
;
import
java.util.Objects
;
@Service
public
class
AuthServiceImpl
implements
AuthService
{
@Autowired
@Qualifier
(
"sysUserServiceImpl"
)
private
ISysUserService
iSysUserService
;
private
final
AuthenticationManager
authenticationManager
;
private
final
JwtTokenProvider
jwtTokenProvider
;
...
...
@@ -33,12 +44,24 @@ public class AuthServiceImpl implements AuthService {
@Override
public
LoginResponse
login
(
LoginRequest
loginRequest
)
{
// 通过Feign调用yd-user-service服务获取用户信息
SysUser
sysUser
=
iSysUserService
.
queryOneByName
(
loginRequest
.
getUsername
());
if
(
Objects
.
isNull
(
sysUser
))
{
throw
new
UsernameNotFoundException
(
"用户不存在"
);
}
//密码:SM3国密算法
//生成盐值
String
salt
=
sysUser
.
getPasswordSalt
();
//生成加密密码:带盐的SM3哈希
String
hashedPassword
=
SM3Util
.
hashWithSalt
(
loginRequest
.
getPassword
(),
salt
);
// 1. 创建未认证的Authentication对象
// - 第一个参数:用户名(作为身份主体)
// - 第二个参数:原始密码(作为凭证)
Authentication
authentication
=
new
UsernamePasswordAuthenticationToken
(
loginRequest
.
getUsername
(),
loginRequest
.
getPassword
()
hashedPassword
);
// 2. 执行Spring Security认证流程(核心步骤)
...
...
yd-auth-core/src/main/java/com/yd/auth/core/service/impl/AuthUserDetailsService.java
View file @
243a95c0
...
...
@@ -5,6 +5,7 @@ import com.yd.user.service.model.SysUser;
import
com.yd.user.service.service.ISysUserService
;
import
org.springframework.beans.BeanUtils
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Qualifier
;
import
org.springframework.security.core.userdetails.UserDetails
;
import
org.springframework.security.core.userdetails.UserDetailsService
;
import
org.springframework.security.core.userdetails.UsernameNotFoundException
;
...
...
@@ -20,6 +21,7 @@ import java.util.Objects;
public
class
AuthUserDetailsService
implements
UserDetailsService
{
@Autowired
@Qualifier
(
"sysUserServiceImpl"
)
private
ISysUserService
iSysUserService
;
@Override
...
...
@@ -33,7 +35,7 @@ public class AuthUserDetailsService implements UserDetailsService {
}
authUserDto
=
new
AuthUserDto
();
BeanUtils
.
copyProperties
(
sysUser
,
authUserDto
);
authUserDto
.
setUsername
(
sysUser
.
getUserName
());
// 查询用户角色 TODO
// authUserDto.setRoles(roles);
...
...
yd-auth-core/src/main/java/com/yd/auth/core/utils/SecurityUtil.java
0 → 100644
View file @
243a95c0
package
com
.
yd
.
auth
.
core
.
utils
;
import
com.yd.auth.core.dto.AuthUserDto
;
import
com.yd.common.exception.BusinessException
;
import
org.springframework.security.core.Authentication
;
import
org.springframework.security.core.context.SecurityContextHolder
;
public
class
SecurityUtil
{
/**
* 获取当前登录用户信息
* @return
*/
public
static
AuthUserDto
getCurrentLoginUser
()
{
// 从 SecurityContext 获取认证信息
Authentication
authentication
=
SecurityContextHolder
.
getContext
().
getAuthentication
();
if
(
authentication
==
null
)
{
throw
new
BusinessException
(
"用户未登录!"
);
}
if
(!(
authentication
.
getPrincipal
()
instanceof
AuthUserDto
))
{
throw
new
BusinessException
(
"用户未登录!"
);
}
AuthUserDto
currentUser
=
(
AuthUserDto
)
authentication
.
getPrincipal
();
return
currentUser
;
}
}
yd-auth-core/src/main/resources/bootstrap.yml
View file @
243a95c0
...
...
@@ -61,6 +61,7 @@ spring:
namespace
:
${spring.cloud.nacos.config.namespace}
# nacos的ip地址和端口
server-addr
:
${spring.cloud.nacos.config.server-addr}
group
:
YD_GROUP
---
spring
:
profiles
:
prod
...
...
yd-auth-core/target/maven-archiver/pom.properties
View file @
243a95c0
#Generated by Maven
#
Mon Jul 28 18:02:31
CST 2025
#
Fri Aug 22 10:56:43
CST 2025
version
=
1.0-SNAPSHOT
groupId
=
com.yd
artifactId
=
yd-auth-core
yd-common/pom.xml
View file @
243a95c0
...
...
@@ -37,6 +37,10 @@
<artifactId>
spring-cloud-starter-openfeign
</artifactId>
</dependency>
<dependency>
<groupId>
org.springframework.cloud
</groupId>
<artifactId>
spring-cloud-starter-loadbalancer
</artifactId>
</dependency>
<dependency>
<groupId>
org.apache.commons
</groupId>
<artifactId>
commons-lang3
</artifactId>
</dependency>
...
...
yd-common/src/main/java/com/yd/common/constant/ServerNameConstants.java
View file @
243a95c0
...
...
@@ -25,4 +25,18 @@ public class ServerNameConstants {
*/
public
static
String
ydScrmApi
=
"yd-scrm-api"
;
/**
* yd-oss-api OSS文件服务接口模块服务名称
*/
public
static
String
ydOssApi
=
"yd-oss-api"
;
/**
* yd-insurance-base-api 银盾保险基础数据服务接口模块服务名称
*/
public
static
String
ydInsuranceBaseApi
=
"yd-insurance-base-api"
;
/**
* yd-csf-api 香港保险服务接口模块服务名称
*/
public
static
String
ydCsfApi
=
"yd-csf-api"
;
}
yd-common/src/main/java/com/yd/common/enums/CommonEnum.java
View file @
243a95c0
...
...
@@ -5,12 +5,31 @@ package com.yd.common.enums;
*/
public
enum
CommonEnum
{
//业务唯一标识id的类型
//业务唯一标识id的类型
枚举
UID_TYPE_TENANT
(
"tenant"
,
"租户"
),
UID_TYPE_PROJECT
(
"project"
,
"项目"
),
UID_TYPE_USER
(
"user"
,
"用户"
),
UID_TYPE_ROLE
(
"role"
,
"角色"
),
UID_TYPE_MENU
(
"menu"
,
"菜单"
),
UID_TYPE_DEPT
(
"dept"
,
"部门"
),
UID_TYPE_INSURANCE_PRODUCT
(
"insurance_product"
,
"保险产品"
),
UID_TYPE_INSURANCE_PRODUCT_PLAN
(
"insurance_product_plan"
,
"保险产品计划"
),
UID_TYPE_INSURANCE_ADDITIONAL_PRODUCT
(
"insurance_additional_product"
,
"保险附加产品"
),
UID_TYPE_OSS_FILE
(
"oss_file"
,
"OSS文件元数据"
),
//作用域枚举
SCOPE_SYS
(
"1"
,
"系统级(全局)"
),
SCOPE_TENANT
(
"2"
,
"租户级"
),
SCOPE_PROJECT
(
"3"
,
"项目级"
),
//作用域对应的数据范围枚举
DATA_SCOPE_PUBLIC
(
"0"
,
"公开"
),
DATA_SCOPE_PRIVATE
(
"1"
,
"私有"
),
//操作来源枚举
OPR_SOURCE_ADD
(
"1"
,
"添加"
),
OPR_SOURCE_EDIT
(
"2"
,
"编辑"
),
;
...
...
yd-common/src/main/java/com/yd/common/enums/MenuTypeEnum.java
0 → 100644
View file @
243a95c0
package
com
.
yd
.
common
.
enums
;
/**
* 菜单类型枚举
*/
public
enum
MenuTypeEnum
{
//菜单类型枚举
ML
(
"1"
,
"目录"
),
CD
(
"2"
,
"菜单"
),
AN
(
"3"
,
"按钮"
),
;
//编码
private
String
code
;
//名称
private
String
name
;
//构造函数
MenuTypeEnum
(
String
code
,
String
name
)
{
this
.
code
=
code
;
this
.
name
=
name
;
}
public
String
getCode
()
{
return
code
;
}
public
String
getName
()
{
return
name
;
}
}
yd-common/src/main/java/com/yd/common/enums/ResultCode.java
View file @
243a95c0
...
...
@@ -12,6 +12,14 @@ public enum ResultCode {
FAIL
(
500
,
"操作失败"
,
""
)
,
NULL_ERROR
(
201
,
"数据不存在"
,
""
)
,
TENANT_NAME_EXISTS
(
202
,
"租户名称已存在"
,
""
)
,
PROJECT_NAME_EXISTS
(
203
,
"项目名称已存在"
,
""
)
,
ROLE_NAME_EXISTS
(
204
,
"角色名称已存在"
,
""
)
,
MENU_NAME_EXISTS
(
205
,
"菜单名称已存在"
,
""
)
,
DEPT_NAME_EXISTS
(
206
,
"部门名称已存在"
,
""
)
,
PRODUCT_NAME_EXISTS
(
207
,
"保险产品名称已存在"
,
""
)
,
PLAN_NAME_EXISTS
(
208
,
"保险产品计划名称已存在"
,
""
)
,
ADDITIONAL_PRODUCT_NAME_EXISTS
(
209
,
"保险附加产品名称已存在"
,
""
)
,
USER_NOT_EXISTS
(
300
,
"用户不存在"
,
""
)
,
PARAM_CHECK_ERROR
(
4001
,
"参数校验异常"
,
""
),
...
...
yd-common/src/main/java/com/yd/common/exception/BusinessException.java
View file @
243a95c0
package
com
.
yd
.
common
.
exception
;
import
com.yd.common.enums.ResultCode
;
import
lombok.Getter
;
/**
...
...
yd-common/src/main/java/com/yd/common/utils/Menu.java
0 → 100644
View file @
243a95c0
package
com
.
yd
.
common
.
utils
;
import
java.util.List
;
public
class
Menu
{
private
Long
id
;
private
Long
parentId
;
private
String
name
;
private
Integer
orderNum
;
private
String
path
;
private
String
icon
;
private
List
<
Menu
>
children
;
// 构造方法
public
Menu
(
Long
id
,
Long
parentId
,
String
name
,
Integer
orderNum
,
String
path
,
String
icon
)
{
this
.
id
=
id
;
this
.
parentId
=
parentId
;
this
.
name
=
name
;
this
.
orderNum
=
orderNum
;
this
.
path
=
path
;
this
.
icon
=
icon
;
}
// getter 和 setter 方法
public
Long
getId
()
{
return
id
;
}
public
void
setId
(
Long
id
)
{
this
.
id
=
id
;
}
public
Long
getParentId
()
{
return
parentId
;
}
public
void
setParentId
(
Long
parentId
)
{
this
.
parentId
=
parentId
;
}
public
String
getName
()
{
return
name
;
}
public
void
setName
(
String
name
)
{
this
.
name
=
name
;
}
public
Integer
getOrderNum
()
{
return
orderNum
;
}
public
void
setOrderNum
(
Integer
orderNum
)
{
this
.
orderNum
=
orderNum
;
}
public
String
getPath
()
{
return
path
;
}
public
void
setPath
(
String
path
)
{
this
.
path
=
path
;
}
public
String
getIcon
()
{
return
icon
;
}
public
void
setIcon
(
String
icon
)
{
this
.
icon
=
icon
;
}
public
List
<
Menu
>
getChildren
()
{
return
children
;
}
public
void
setChildren
(
List
<
Menu
>
children
)
{
this
.
children
=
children
;
}
@Override
public
String
toString
()
{
return
"Menu{"
+
"id="
+
id
+
", name='"
+
name
+
'\''
+
", children="
+
(
children
!=
null
?
children
.
size
()
:
0
)
+
'}'
;
}
}
yd-common/src/main/java/com/yd/common/utils/RandomStringGenerator.java
View file @
243a95c0
...
...
@@ -36,7 +36,7 @@ public class RandomStringGenerator {
* @param uidType 业务标识类型
* @return 业务标识类型+32位随机字符串
*/
public
static
String
generate
Ui
d32
(
String
uidType
)
{
public
static
String
generate
BizI
d32
(
String
uidType
)
{
return
uidType
+
"_"
+
generate
(
32
,
true
);
}
...
...
@@ -45,7 +45,7 @@ public class RandomStringGenerator {
* @param uidType 业务标识类型
* @return 业务标识类型+16位随机字符串
*/
public
static
String
generate
Ui
d16
(
String
uidType
)
{
public
static
String
generate
BizI
d16
(
String
uidType
)
{
return
uidType
+
"_"
+
generate
(
16
,
true
);
}
...
...
@@ -58,6 +58,6 @@ public class RandomStringGenerator {
String
random32
=
generate
(
32
,
false
);
System
.
out
.
println
(
"32位: "
+
random32
);
System
.
out
.
println
(
generate
Ui
d16
(
CommonEnum
.
UID_TYPE_USER
.
getCode
()));
System
.
out
.
println
(
generate
BizI
d16
(
CommonEnum
.
UID_TYPE_USER
.
getCode
()));
}
}
yd-common/src/main/java/com/yd/common/utils/SM2Util.java
0 → 100644
View file @
243a95c0
package
com
.
yd
.
common
.
utils
;
import
org.bouncycastle.crypto.engines.SM2Engine
;
import
org.bouncycastle.crypto.params.ECPrivateKeyParameters
;
import
org.bouncycastle.crypto.params.ECPublicKeyParameters
;
import
org.bouncycastle.crypto.params.ParametersWithRandom
;
import
org.bouncycastle.jce.provider.BouncyCastleProvider
;
import
org.bouncycastle.jce.spec.ECParameterSpec
;
import
org.bouncycastle.jce.ECNamedCurveTable
;
import
org.bouncycastle.util.encoders.Hex
;
import
java.security.*
;
/**
* SM2国密算法工具类
*/
public
class
SM2Util
{
static
{
Security
.
addProvider
(
new
BouncyCastleProvider
());
}
// 生成SM2密钥对
public
static
KeyPair
generateKeyPair
()
throws
Exception
{
ECParameterSpec
ecSpec
=
ECNamedCurveTable
.
getParameterSpec
(
"sm2p256v1"
);
KeyPairGenerator
kpg
=
KeyPairGenerator
.
getInstance
(
"EC"
,
"BC"
);
kpg
.
initialize
(
ecSpec
,
new
SecureRandom
());
return
kpg
.
generateKeyPair
();
}
// SM2加密
public
static
String
encrypt
(
String
publicKeyHex
,
String
data
)
throws
Exception
{
ECPublicKeyParameters
publicKey
=
getPublicKeyFromHex
(
publicKeyHex
);
SM2Engine
engine
=
new
SM2Engine
();
engine
.
init
(
true
,
new
ParametersWithRandom
(
publicKey
,
new
SecureRandom
()));
byte
[]
dataBytes
=
data
.
getBytes
();
byte
[]
encrypted
=
engine
.
processBlock
(
dataBytes
,
0
,
dataBytes
.
length
);
return
Hex
.
toHexString
(
encrypted
);
}
// SM2解密
public
static
String
decrypt
(
String
privateKeyHex
,
String
encryptedData
)
throws
Exception
{
ECPrivateKeyParameters
privateKey
=
getPrivateKeyFromHex
(
privateKeyHex
);
SM2Engine
engine
=
new
SM2Engine
();
engine
.
init
(
false
,
privateKey
);
byte
[]
encryptedBytes
=
Hex
.
decode
(
encryptedData
);
byte
[]
decrypted
=
engine
.
processBlock
(
encryptedBytes
,
0
,
encryptedBytes
.
length
);
return
new
String
(
decrypted
);
}
// 从十六进制字符串获取公钥
private
static
ECPublicKeyParameters
getPublicKeyFromHex
(
String
publicKeyHex
)
{
// 实现细节省略
return
null
;
}
// 从十六进制字符串获取私钥
private
static
ECPrivateKeyParameters
getPrivateKeyFromHex
(
String
privateKeyHex
)
{
// 实现细节省略
return
null
;
}
}
yd-common/src/main/java/com/yd/common/utils/SM3Util.java
0 → 100644
View file @
243a95c0
package
com
.
yd
.
common
.
utils
;
import
org.bouncycastle.crypto.digests.SM3Digest
;
import
org.bouncycastle.util.encoders.Hex
;
import
java.security.SecureRandom
;
import
java.util.Base64
;
/**
* SM3国密算法工具类
*/
public
class
SM3Util
{
// 生成盐值
public
static
String
generateSalt
()
{
SecureRandom
random
=
new
SecureRandom
();
byte
[]
salt
=
new
byte
[
16
];
random
.
nextBytes
(
salt
);
return
Base64
.
getEncoder
().
encodeToString
(
salt
);
}
// SM3哈希计算
public
static
String
hash
(
String
data
)
{
SM3Digest
digest
=
new
SM3Digest
();
byte
[]
dataBytes
=
data
.
getBytes
();
digest
.
update
(
dataBytes
,
0
,
dataBytes
.
length
);
byte
[]
result
=
new
byte
[
digest
.
getDigestSize
()];
digest
.
doFinal
(
result
,
0
);
return
Hex
.
toHexString
(
result
);
}
// 带盐的SM3哈希
public
static
String
hashWithSalt
(
String
data
,
String
salt
)
{
return
hash
(
data
+
salt
);
}
// 验证密码
public
static
boolean
verifyPassword
(
String
inputPassword
,
String
storedHash
,
String
salt
)
{
String
hashedInput
=
hashWithSalt
(
inputPassword
,
salt
);
return
hashedInput
.
equals
(
storedHash
);
}
public
static
void
main
(
String
[]
args
)
{
// 1. 处理密码 - 使用SM3加盐哈希
String
password
=
"123456"
;
String
salt
=
SM3Util
.
generateSalt
();
// String salt = "hdcgRnNrvxNShm/VuNRqfA==";
String
hashedPassword
=
SM3Util
.
hashWithSalt
(
password
,
salt
);
//05c6ff03f779dd0fab34fb67c6c0be1c8cfb9a7cc241e86c23a8d9c05a8ea939
System
.
out
.
println
(
hashedPassword
);
}
}
yd-common/src/main/java/com/yd/common/utils/TreeMenuExample.java
0 → 100644
View file @
243a95c0
package
com
.
yd
.
common
.
utils
;
import
java.util.ArrayList
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
public
class
TreeMenuExample
{
public
static
void
main
(
String
[]
args
)
{
// 1. 创建菜单列表(模拟数据库查询结果)
List
<
Menu
>
menuList
=
new
ArrayList
<>();
menuList
.
add
(
new
Menu
(
1L
,
0L
,
"系统管理"
,
1
,
"/system"
,
"system"
));
menuList
.
add
(
new
Menu
(
2L
,
1L
,
"用户管理"
,
1
,
"/system/user"
,
"user"
));
menuList
.
add
(
new
Menu
(
3L
,
1L
,
"角色管理"
,
2
,
"/system/role"
,
"peoples"
));
menuList
.
add
(
new
Menu
(
4L
,
0L
,
"监控管理"
,
2
,
"/monitor"
,
"monitor"
));
menuList
.
add
(
new
Menu
(
5L
,
4L
,
"在线用户"
,
1
,
"/monitor/online"
,
"online"
));
menuList
.
add
(
new
Menu
(
6L
,
4L
,
"系统日志"
,
2
,
"/monitor/log"
,
"log"
));
menuList
.
add
(
new
Menu
(
7L
,
2L
,
"用户新增"
,
1
,
null
,
null
));
menuList
.
add
(
new
Menu
(
8L
,
2L
,
"用户编辑"
,
2
,
null
,
null
));
// 2. 构建树形结构
List
<
Menu
>
treeMenu
=
TreeUtils
.
buildTree
(
menuList
,
Menu:
:
getId
,
// 获取节点ID
Menu:
:
getParentId
,
// 获取父节点ID
(
parent
,
children
)
->
parent
.
setChildren
(
children
),
// 设置子节点
0L
// 根节点的父ID值
);
// 3. 打印树形结构
// printTree(treeMenu, 0);
// 4. 创建树形JSON
List
<
Map
<
String
,
Object
>>
treeJson
=
TreeUtils
.
createTreeJson
(
treeMenu
,
Menu:
:
getChildren
,
menu
->
{
Map
<
String
,
Object
>
map
=
new
HashMap
<>();
map
.
put
(
"id"
,
menu
.
getId
());
map
.
put
(
"name"
,
menu
.
getName
());
map
.
put
(
"path"
,
menu
.
getPath
());
map
.
put
(
"icon"
,
menu
.
getIcon
());
return
map
;
},
"/"
);
System
.
out
.
println
(
"\n树形JSON结构:"
);
System
.
out
.
println
(
treeJson
);
}
// 递归打印树形结构
private
static
void
printTree
(
List
<
Menu
>
menus
,
int
level
)
{
if
(
menus
==
null
)
return
;
for
(
Menu
menu
:
menus
)
{
for
(
int
i
=
0
;
i
<
level
;
i
++)
{
System
.
out
.
print
(
" "
);
}
System
.
out
.
println
(
"├─ "
+
menu
.
getName
()
+
" (ID: "
+
menu
.
getId
()
+
")"
);
if
(
menu
.
getChildren
()
!=
null
&&
!
menu
.
getChildren
().
isEmpty
())
{
printTree
(
menu
.
getChildren
(),
level
+
1
);
}
}
}
}
yd-common/src/main/java/com/yd/common/utils/TreeUtils.java
0 → 100644
View file @
243a95c0
package
com
.
yd
.
common
.
utils
;
import
java.util.ArrayList
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Objects
;
import
java.util.function.Function
;
import
java.util.stream.Collectors
;
/**
* 树形工具类 - 用于将扁平列表转换为树形结构
*/
public
class
TreeUtils
{
/**
* 将扁平列表转换为树形结构
*
* @param list 原始数据列表
* @param idGetter 获取节点ID的方法
* @param parentIdGetter 获取父节点ID的方法
* @param childrenSetter 设置子节点的方法
* @param rootParentId 根节点的父ID值(通常为0或null)
* @param <T> 节点类型
* @param <R> ID类型
* @return 树形结构列表
*/
public
static
<
T
,
R
>
List
<
T
>
buildTree
(
List
<
T
>
list
,
Function
<
T
,
R
>
idGetter
,
Function
<
T
,
R
>
parentIdGetter
,
ChildrenSetter
<
T
>
childrenSetter
,
R
rootParentId
)
{
// 1. 创建节点映射表(ID -> 节点)
Map
<
R
,
T
>
nodeMap
=
list
.
stream
()
.
collect
(
Collectors
.
toMap
(
idGetter
,
Function
.
identity
()));
// 2. 创建结果列表(根节点列表)
List
<
T
>
rootNodes
=
new
ArrayList
<>();
// 3. 遍历所有节点,构建父子关系
for
(
T
node
:
list
)
{
R
parentId
=
parentIdGetter
.
apply
(
node
);
// 根节点处理
if
(
Objects
.
equals
(
parentId
,
rootParentId
))
{
rootNodes
.
add
(
node
);
continue
;
}
// 非根节点处理
T
parentNode
=
nodeMap
.
get
(
parentId
);
if
(
parentNode
!=
null
)
{
List
<
T
>
children
=
childrenSetter
.
getChildren
(
parentNode
);
if
(
children
==
null
)
{
children
=
new
ArrayList
<>();
childrenSetter
.
setChildren
(
parentNode
,
children
);
}
children
.
add
(
node
);
}
}
// 4. 对树进行排序(可选)
sortTree
(
rootNodes
,
childrenSetter
);
return
rootNodes
;
}
/**
* 递归排序树形结构(按orderNum排序)
*
* @param nodes 当前层节点列表
* @param childrenSetter 子节点访问器
* @param <T> 节点类型
*/
public
static
<
T
>
void
sortTree
(
List
<
T
>
nodes
,
ChildrenSetter
<
T
>
childrenSetter
)
{
if
(
nodes
==
null
||
nodes
.
isEmpty
())
{
return
;
}
// 按orderNum排序(如果没有orderNum属性,需要自定义排序逻辑)
nodes
.
sort
((
a
,
b
)
->
{
try
{
// 使用反射获取orderNum属性
java
.
lang
.
reflect
.
Method
getOrderNum
=
a
.
getClass
().
getMethod
(
"getOrderNum"
);
Integer
orderNumA
=
(
Integer
)
getOrderNum
.
invoke
(
a
);
Integer
orderNumB
=
(
Integer
)
getOrderNum
.
invoke
(
b
);
return
Integer
.
compare
(
orderNumA
==
null
?
0
:
orderNumA
,
orderNumB
==
null
?
0
:
orderNumB
);
}
catch
(
Exception
e
)
{
// 如果没有orderNum属性,则按ID排序
try
{
java
.
lang
.
reflect
.
Method
getId
=
a
.
getClass
().
getMethod
(
"getId"
);
Comparable
idA
=
(
Comparable
)
getId
.
invoke
(
a
);
Comparable
idB
=
(
Comparable
)
getId
.
invoke
(
b
);
return
idA
.
compareTo
(
idB
);
}
catch
(
Exception
ex
)
{
return
0
;
}
}
});
// 递归排序子节点
for
(
T
node
:
nodes
)
{
List
<
T
>
children
=
childrenSetter
.
getChildren
(
node
);
if
(
children
!=
null
&&
!
children
.
isEmpty
())
{
sortTree
(
children
,
childrenSetter
);
}
}
}
/**
* 从树形结构中查找指定节点
*
* @param tree 树形结构
* @param targetId 目标ID
* @param idGetter ID获取器
* @param childrenGetter 子节点获取器
* @param <T> 节点类型
* @param <R> ID类型
* @return 找到的节点,未找到返回null
*/
public
static
<
T
,
R
>
T
findNodeInTree
(
List
<
T
>
tree
,
R
targetId
,
Function
<
T
,
R
>
idGetter
,
Function
<
T
,
List
<
T
>>
childrenGetter
)
{
for
(
T
node
:
tree
)
{
// 检查当前节点
if
(
Objects
.
equals
(
idGetter
.
apply
(
node
),
targetId
))
{
return
node
;
}
// 递归检查子节点
List
<
T
>
children
=
childrenGetter
.
apply
(
node
);
if
(
children
!=
null
&&
!
children
.
isEmpty
())
{
T
found
=
findNodeInTree
(
children
,
targetId
,
idGetter
,
childrenGetter
);
if
(
found
!=
null
)
{
return
found
;
}
}
}
return
null
;
}
/**
* 将树形结构扁平化为列表
*
* @param tree 树形结构
* @param childrenGetter 子节点获取器
* @param <T> 节点类型
* @return 扁平化列表
*/
public
static
<
T
>
List
<
T
>
flattenTree
(
List
<
T
>
tree
,
Function
<
T
,
List
<
T
>>
childrenGetter
)
{
List
<
T
>
result
=
new
ArrayList
<>();
flattenTree
(
tree
,
childrenGetter
,
result
);
return
result
;
}
private
static
<
T
>
void
flattenTree
(
List
<
T
>
nodes
,
Function
<
T
,
List
<
T
>>
childrenGetter
,
List
<
T
>
result
)
{
if
(
nodes
==
null
)
return
;
for
(
T
node
:
nodes
)
{
result
.
add
(
node
);
List
<
T
>
children
=
childrenGetter
.
apply
(
node
);
if
(
children
!=
null
&&
!
children
.
isEmpty
())
{
flattenTree
(
children
,
childrenGetter
,
result
);
}
}
}
/**
* 子节点设置器接口
*
* @param <T> 节点类型
*/
@FunctionalInterface
public
interface
ChildrenSetter
<
T
>
{
/**
* 设置子节点列表
*
* @param parent 父节点
* @param children 子节点列表
*/
void
setChildren
(
T
parent
,
List
<
T
>
children
);
/**
* 获取子节点列表
*
* @param parent 父节点
* @return 子节点列表
*/
default
List
<
T
>
getChildren
(
T
parent
)
{
try
{
// 使用反射获取children属性
java
.
lang
.
reflect
.
Method
getChildren
=
parent
.
getClass
().
getMethod
(
"getChildren"
);
return
(
List
<
T
>)
getChildren
.
invoke
(
parent
);
}
catch
(
Exception
e
)
{
return
null
;
}
}
}
/**
* 创建树形菜单的JSON结构(带层级路径)
*
* @param tree 树形结构
* @param childrenGetter 子节点获取器
* @param mapper 节点转换器
* @param <T> 原始节点类型
* @param <R> 结果类型
* @return 树形JSON结构
*/
public
static
<
T
,
R
>
List
<
Map
<
String
,
Object
>>
createTreeJson
(
List
<
T
>
tree
,
Function
<
T
,
List
<
T
>>
childrenGetter
,
Function
<
T
,
R
>
mapper
,
String
pathSeparator
)
{
List
<
Map
<
String
,
Object
>>
result
=
new
ArrayList
<>();
createTreeJson
(
tree
,
childrenGetter
,
mapper
,
result
,
""
,
pathSeparator
);
return
result
;
}
private
static
<
T
,
R
>
void
createTreeJson
(
List
<
T
>
nodes
,
Function
<
T
,
List
<
T
>>
childrenGetter
,
Function
<
T
,
R
>
mapper
,
List
<
Map
<
String
,
Object
>>
result
,
String
parentPath
,
String
pathSeparator
)
{
if
(
nodes
==
null
)
return
;
for
(
T
node
:
nodes
)
{
Map
<
String
,
Object
>
nodeMap
=
new
HashMap
<>();
// 添加节点数据
nodeMap
.
put
(
"data"
,
mapper
.
apply
(
node
));
// 创建当前节点路径
try
{
java
.
lang
.
reflect
.
Method
getId
=
node
.
getClass
().
getMethod
(
"getId"
);
Object
id
=
getId
.
invoke
(
node
);
String
currentPath
=
parentPath
.
isEmpty
()
?
id
.
toString
()
:
parentPath
+
pathSeparator
+
id
;
nodeMap
.
put
(
"path"
,
currentPath
);
}
catch
(
Exception
e
)
{
nodeMap
.
put
(
"path"
,
parentPath
);
}
// 处理子节点
List
<
T
>
children
=
childrenGetter
.
apply
(
node
);
if
(
children
!=
null
&&
!
children
.
isEmpty
())
{
List
<
Map
<
String
,
Object
>>
childrenJson
=
new
ArrayList
<>();
createTreeJson
(
children
,
childrenGetter
,
mapper
,
childrenJson
,
(
String
)
nodeMap
.
get
(
"path"
),
pathSeparator
);
nodeMap
.
put
(
"children"
,
childrenJson
);
}
result
.
add
(
nodeMap
);
}
}
}
yd-common/target/maven-archiver/pom.properties
View file @
243a95c0
#Generated by Maven
#
Mon Jul 28 18:02:10
CST 2025
#
Tue Aug 26 16:56:01
CST 2025
version
=
1.0-SNAPSHOT
groupId
=
com.yd
artifactId
=
yd-common
yd-feign/target/maven-archiver/pom.properties
View file @
243a95c0
#Generated by Maven
#
Mon Jul 28 18:02:38
CST 2025
#
Fri Aug 22 10:56:50
CST 2025
version
=
1.0-SNAPSHOT
groupId
=
com.yd
artifactId
=
yd-feign
yd-framework/pom.xml
View file @
243a95c0
...
...
@@ -34,5 +34,9 @@
<groupId>
org.projectlombok
</groupId>
<artifactId>
lombok
</artifactId>
</dependency>
<dependency>
<groupId>
org.springframework.security
</groupId>
<artifactId>
spring-security-core
</artifactId>
</dependency>
</dependencies>
</project>
yd-framework/src/main/java/com/yd/framework/handler/GlobalExceptionHandler.java
View file @
243a95c0
...
...
@@ -4,6 +4,7 @@ import com.yd.common.enums.ResultCode;
import
com.yd.common.exception.BusinessException
;
import
com.yd.common.result.Result
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.security.authentication.BadCredentialsException
;
import
org.springframework.validation.BindingResult
;
import
org.springframework.validation.FieldError
;
import
org.springframework.web.bind.MethodArgumentNotValidException
;
...
...
@@ -62,6 +63,14 @@ public class GlobalExceptionHandler {
return
Result
.
fail
(
ResultCode
.
PARAM_CHECK_ERROR
.
getCode
(),
message
);
}
// 专门捕获 BadCredentialsException,返回“密码错误”的自定义响应
@ExceptionHandler
(
BadCredentialsException
.
class
)
public
Result
<?>
handleBadCredentialsException
(
BadCredentialsException
e
)
{
log
.
error
(
"认证失败:{}"
,
e
.
getMessage
());
// 返回自定义的错误码和“密码错误”提示(而非模糊的“用户名或密码错误”)
return
Result
.
fail
(
"认证失败:密码错误,请重新输入"
);
}
/**
* 处理其他异常
*/
...
...
yd-framework/target/maven-archiver/pom.properties
View file @
243a95c0
#Generated by Maven
#
Mon Jul 28 18:02:41
CST 2025
#
Fri Aug 22 10:56:35
CST 2025
version
=
1.0-SNAPSHOT
groupId
=
com.yd
artifactId
=
yd-framework
yd-gateway/pom.xml
View file @
243a95c0
...
...
@@ -18,26 +18,56 @@
<groupId>
org.springframework.cloud
</groupId>
<artifactId>
spring-cloud-starter-gateway
</artifactId>
</dependency>
<dependency>
<groupId>
com.alibaba.cloud
</groupId>
<artifactId>
spring-cloud-starter-alibaba-nacos-discovery
</artifactId>
</dependency>
<!-- SpringCloud
Openfeign
-->
<!-- SpringCloud
Alibaba Nacos Config
-->
<dependency>
<groupId>
org.springframework
.cloud
</groupId>
<artifactId>
spring-cloud-starter-
openfeign
</artifactId>
<groupId>
com.alibaba
.cloud
</groupId>
<artifactId>
spring-cloud-starter-
alibaba-nacos-config
</artifactId>
</dependency>
<dependency>
<groupId>
com.yd
</groupId>
<artifactId>
yd-auth-core
</artifactId>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-web
</artifactId>
</dependency>
<dependency>
<groupId>
com.yd
</groupId>
<artifactId>
yd-common
</artifactId>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter
</artifactId>
</dependency>
<!--对于bootstrap.properties/bootstrap.yaml配置文件(我们合起来成为Bootstrap配置文件)的支持,需要导入如下的依赖 -->
<dependency>
<groupId>
org.springframework.cloud
</groupId>
<artifactId>
spring-cloud-starter-bootstrap
</artifactId>
</dependency>
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-actuator
</artifactId>
</dependency>
<!-- JWT 依赖 -->
<dependency>
<groupId>
io.jsonwebtoken
</groupId>
<artifactId>
jjwt-api
</artifactId>
</dependency>
<dependency>
<groupId>
io.jsonwebtoken
</groupId>
<artifactId>
jjwt-impl
</artifactId>
</dependency>
<dependency>
<groupId>
io.jsonwebtoken
</groupId>
<artifactId>
jjwt-jackson
</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>com.yd</groupId>-->
<!-- <artifactId>yd-auth-core</artifactId>-->
<!-- </dependency>-->
<dependency>
<groupId>
com.yd
</groupId>
<artifactId>
yd-common
</artifactId>
</dependency>
</dependencies>
</project>
yd-gateway/src/main/java/com/yd/gateway/GatewayApplication.java
View file @
243a95c0
...
...
@@ -3,19 +3,18 @@ package com.yd.gateway;
import
com.yd.common.constant.ServerNameConstants
;
import
org.springframework.boot.autoconfigure.SpringBootApplication
;
import
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
;
import
org.springframework.boot.builder.SpringApplicationBuilder
;
import
org.springframework.cloud.openfeign.EnableFeignClients
;
/**
* 网关启动程序
*/
@SpringBootApplication
(
exclude
=
{
DataSourceAutoConfiguration
.
class
}
)
@EnableFeignClients
(
basePackages
=
"com.yd
.gateway.**
"
)
@SpringBootApplication
(
scanBasePackages
=
"com.yd"
)
@EnableFeignClients
(
basePackages
=
"com.yd"
)
public
class
GatewayApplication
{
public
static
void
main
(
String
[]
args
)
{
new
SpringApplicationBuilder
(
GatewayApplication
.
class
)
.
properties
(
"spring.config.name:bootstrap"
,
"config/bootstrap.yml"
)
//
.properties("spring.config.name:bootstrap", "config/bootstrap.yml")
.
properties
(
"spring.application.name="
+
ServerNameConstants
.
ydGateway
)
.
build
().
run
(
args
);
System
.
out
.
println
(
"(♥◠‿◠)ノ゙ yd-gateway网关启动成功 ლ(´ڡ`ლ)゙ "
);
...
...
yd-gateway/src/main/java/com/yd/gateway/config/CorsConfig.java
0 → 100644
View file @
243a95c0
package
com
.
yd
.
gateway
.
config
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.web.cors.CorsConfiguration
;
import
org.springframework.web.cors.reactive.CorsWebFilter
;
import
org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource
;
import
org.springframework.web.util.pattern.PathPatternParser
;
@Configuration
public
class
CorsConfig
{
@Bean
public
CorsWebFilter
corsFilter
()
{
CorsConfiguration
config
=
new
CorsConfiguration
();
config
.
addAllowedMethod
(
"*"
);
config
.
addAllowedOrigin
(
"*"
);
config
.
addAllowedHeader
(
"*"
);
UrlBasedCorsConfigurationSource
source
=
new
UrlBasedCorsConfigurationSource
(
new
PathPatternParser
());
source
.
registerCorsConfiguration
(
"/**"
,
config
);
return
new
CorsWebFilter
(
source
);
}
}
yd-gateway/src/main/java/com/yd/gateway/config/GatewayJwtAuthFilterConfig.java
0 → 100644
View file @
243a95c0
package
com
.
yd
.
gateway
.
config
;
import
com.yd.gateway.exception.JwtAuthException
;
import
com.yd.gateway.utils.JwtTokenUtil
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.cloud.gateway.filter.GlobalFilter
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.core.Ordered
;
import
org.springframework.core.annotation.Order
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.web.server.ServerWebExchange
;
import
reactor.core.publisher.Mono
;
/**
* 网关JWT认证过滤器:只做轻量校验(验证token有效性),不查询业务数据
*/
@Configuration
public
class
GatewayJwtAuthFilterConfig
{
@Autowired
private
JwtTokenUtil
jwtTokenUtil
;
/**
* 注册全局过滤器,优先级高于路由过滤器(确保先校验再路由)
*/
@Bean
@Order
(
Ordered
.
HIGHEST_PRECEDENCE
)
// 最高优先级,在路由前执行
public
GlobalFilter
jwtAuthFilter
()
{
return
(
exchange
,
chain
)
->
{
// 1. 获取请求路径,跳过白名单(如登录、Swagger等)
String
path
=
exchange
.
getRequest
().
getPath
().
toString
();
if
(
isWhitelist
(
path
))
{
// 白名单路径直接放行
return
chain
.
filter
(
exchange
);
}
// 2. 从请求头获取token
String
token
=
resolveToken
(
exchange
);
if
(
token
==
null
)
{
// 无token,返回401未授权
return
setUnauthorizedResponse
(
exchange
,
"未提供令牌(Authorization头缺失或格式错误)"
);
}
// 3. 验证token有效性(只做签名、过期等基础校验,不查用户)
try
{
jwtTokenUtil
.
validateToken
(
token
);
// token有效,继续路由到下游服务
return
chain
.
filter
(
exchange
);
}
catch
(
JwtAuthException
e
)
{
// token无效(如过期、签名错误),返回401
return
setUnauthorizedResponse
(
exchange
,
"令牌无效:"
+
e
.
getMessage
());
}
};
}
/**
* 解析请求头中的token(Authorization: Bearer <token>)
*/
private
String
resolveToken
(
ServerWebExchange
exchange
)
{
String
authHeader
=
exchange
.
getRequest
().
getHeaders
().
getFirst
(
"Authorization"
);
if
(
authHeader
!=
null
&&
authHeader
.
startsWith
(
"Bearer "
))
{
return
authHeader
.
substring
(
7
).
trim
();
// 去除"Bearer "前缀
}
return
null
;
}
/**
* 判断路径是否在白名单中(无需认证)
*/
private
boolean
isWhitelist
(
String
path
)
{
// 白名单路径:与SecurityWebFilterChain中的配置保持一致
return
path
.
startsWith
(
"/auth/"
)
||
path
.
startsWith
(
"/swagger-ui/"
)
||
path
.
startsWith
(
"/v3/api-docs/"
);
}
/**
* 设置401响应
*/
private
Mono
<
Void
>
setUnauthorizedResponse
(
ServerWebExchange
exchange
,
String
message
)
{
exchange
.
getResponse
().
setStatusCode
(
HttpStatus
.
UNAUTHORIZED
);
exchange
.
getResponse
().
getHeaders
().
add
(
"Content-Type"
,
"application/json;charset=UTF-8"
);
// 构建错误响应体
String
json
=
"{\"status\":401,\"error\":\"Unauthorized\",\"message\":\""
+
message
+
"\"}"
;
return
exchange
.
getResponse
()
.
writeWith
(
Mono
.
just
(
exchange
.
getResponse
().
bufferFactory
().
wrap
(
json
.
getBytes
())));
}
}
yd-gateway/src/main/java/com/yd/gateway/config/GatewaySecurityConfig.java
View file @
243a95c0
package
com
.
yd
.
gateway
.
config
;
import
com.yd.auth.core.security.JwtTokenProvider
;
import
com.yd.auth.core.security.JwtTokenProvider.JwtAuthenticationException
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity
;
import
org.springframework.security.config.web.server.ServerHttpSecurity
;
import
org.springframework.security.oauth2.jwt.Jwt
;
import
org.springframework.security.web.server.SecurityWebFilterChain
;
import
reactor.core.publisher.Mono
;
@Configuration
@EnableWebFluxSecurity
public
class
GatewaySecurityConfig
{
private
final
JwtTokenProvider
jwtTokenProvider
;
public
GatewaySecurityConfig
(
JwtTokenProvider
jwtTokenProvider
)
{
this
.
jwtTokenProvider
=
jwtTokenProvider
;
}
@Bean
public
SecurityWebFilterChain
securityWebFilterChain
(
ServerHttpSecurity
http
)
{
http
.
csrf
().
disable
()
.
authorizeExchange
(
exchanges
->
exchanges
.
pathMatchers
(
"/auth/**"
,
"/swagger-ui/**"
,
"/v3/api-docs/**"
).
permitAll
()
// 放行认证和Swagger路径
.
anyExchange
().
authenticated
()
// 其他请求需要认证
)
.
oauth2ResourceServer
(
oauth2
->
oauth2
.
jwt
(
jwt
->
jwt
.
jwtDecoder
(
token
->
{
try
{
// 验证令牌有效性
jwtTokenProvider
.
validateToken
(
token
);
// 将字符串转换为 Jwt 对象
Jwt
jwtObject
=
Jwt
.
withTokenValue
(
token
).
build
();
return
Mono
.
just
(
jwtObject
);
}
catch
(
JwtAuthenticationException
e
)
{
return
Mono
.
error
(
e
);
}
})
)
);
return
http
.
build
();
}
}
//package com.yd.gateway.config;
//
//import com.yd.auth.core.security.JwtTokenProvider;
//import com.yd.auth.core.security.JwtTokenProvider.JwtAuthenticationException;
//import io.jsonwebtoken.Claims;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.context.annotation.Bean;
//import org.springframework.context.annotation.Configuration;
//import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
//import org.springframework.security.config.web.server.ServerHttpSecurity;
//import org.springframework.security.oauth2.jwt.Jwt;
//import org.springframework.security.web.server.SecurityWebFilterChain;
//import reactor.core.publisher.Mono;
//
//@Configuration
//@EnableWebFluxSecurity
//public class GatewaySecurityConfig {
//
//
//// private final JwtTokenProvider jwtTokenProvider;
////
//// public GatewaySecurityConfig(JwtTokenProvider jwtTokenProvider) {
//// this.jwtTokenProvider = jwtTokenProvider;
//// }
//
// @Autowired
// private JwtTokenProvider jwtTokenProvider;
//
// @Bean
// public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
// http
// .csrf().disable()
// .authorizeExchange(exchanges -> exchanges
// .pathMatchers(
// "/auth/**",
// "/swagger-ui/**",
// "/v3/api-docs/**"
// ).permitAll() // 放行认证和Swagger路径
// .anyExchange().authenticated() // 其他请求需要认证
// )
// .oauth2ResourceServer(oauth2 -> oauth2
// .jwt(jwt -> jwt
// .jwtDecoder(token -> {
// try {
// // 验证令牌有效性
// jwtTokenProvider.validateToken(token);
//
// // 完整解析 JWT 令牌
// Claims claims = jwtTokenProvider.parseClaims(token);
//
// // 构建完整 JWT 对象
// return Mono.just(new Jwt(
// token,
// claims.getIssuedAt().toInstant(),
// claims.getExpiration().toInstant(),
// jwtTokenProvider.getHeaders(token), // 获取头部信息
// claims
// ));
// } catch (JwtAuthenticationException e) {
// return Mono.error(e);
// }
// })
// )
// );
// return http.build();
// }
//}
yd-gateway/src/main/java/com/yd/gateway/config/RouteDebugFilter.java
0 → 100644
View file @
243a95c0
//package com.yd.gateway.config;
//
//import org.springframework.cloud.gateway.filter.GlobalFilter;
//import org.springframework.context.annotation.Bean;
//import org.springframework.context.annotation.Configuration;
//import reactor.core.publisher.Mono;
//
//@Configuration
//public class RouteDebugFilter {
// @Bean
// public GlobalFilter debugFilter() {
// return (exchange, chain) -> {
// System.out.println("请求路径: " + exchange.getRequest().getPath());
// System.out.println("转发URL: " + exchange.getRequiredAttribute("GATEWAY_REQUEST_URL_ATTR"));
// return chain.filter(exchange);
// };
// }
//}
yd-gateway/src/main/java/com/yd/gateway/exception/JwtAuthException.java
0 → 100644
View file @
243a95c0
package
com
.
yd
.
gateway
.
exception
;
/**
* JWT认证异常
*/
public
class
JwtAuthException
extends
RuntimeException
{
public
JwtAuthException
(
String
message
)
{
super
(
message
);
}
public
JwtAuthException
(
String
message
,
Throwable
cause
)
{
super
(
message
,
cause
);
}
}
yd-gateway/src/main/java/com/yd/gateway/utils/JwtTokenUtil.java
0 → 100644
View file @
243a95c0
package
com
.
yd
.
gateway
.
utils
;
import
com.yd.gateway.exception.JwtAuthException
;
import
io.jsonwebtoken.ExpiredJwtException
;
import
io.jsonwebtoken.Jwts
;
import
io.jsonwebtoken.MalformedJwtException
;
import
io.jsonwebtoken.UnsupportedJwtException
;
import
io.jsonwebtoken.io.Decoders
;
import
io.jsonwebtoken.security.Keys
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.stereotype.Component
;
import
javax.crypto.SecretKey
;
/**
* JWT令牌提供者
* 修复了密钥长度不足的问题,并优化了异常处理
*/
@Component
public
class
JwtTokenUtil
{
// 使用512位长度的密钥(通过配置文件设置)
@Value
(
"${jwt.secret}"
)
private
String
jwtSecret
;
@Value
(
"${jwt.expiration}"
)
// 默认24小时(单位毫秒)
private
int
jwtExpiration
;
/**
* 验证令牌有效性
*/
public
boolean
validateToken
(
String
token
)
{
try
{
Jwts
.
parserBuilder
().
setSigningKey
(
getSigningKey
()).
build
().
parseClaimsJws
(
token
);
return
true
;
}
catch
(
SecurityException
|
MalformedJwtException
e
)
{
throw
new
JwtAuthException
(
"无效的JWT签名"
);
}
catch
(
ExpiredJwtException
e
)
{
throw
new
JwtAuthException
(
"JWT令牌已过期"
);
}
catch
(
UnsupportedJwtException
e
)
{
throw
new
JwtAuthException
(
"不支持的JWT令牌"
);
}
catch
(
IllegalArgumentException
e
)
{
throw
new
JwtAuthException
(
"JWT令牌无效"
);
}
catch
(
Exception
e
)
{
throw
new
JwtAuthException
(
"无效的JWT令牌: "
+
e
.
getMessage
());
}
}
/**
* 获取签名密钥
*/
private
SecretKey
getSigningKey
()
{
try
{
if
(
jwtSecret
==
null
||
jwtSecret
.
trim
().
isEmpty
())
{
throw
new
JwtAuthException
(
"JWT密钥未配置"
);
}
byte
[]
keyBytes
=
Decoders
.
BASE64
.
decode
(
jwtSecret
);
return
Keys
.
hmacShaKeyFor
(
keyBytes
);
}
catch
(
Exception
e
)
{
throw
new
JwtAuthException
(
"获取签名密钥失败: "
+
e
.
getMessage
());
}
}
}
yd-gateway/src/main/resources/banner.txt
0 → 100644
View file @
243a95c0
${AnsiColor.GREEN}
_ _ _ __ __ ____ _ _ ____ _ __ __
| | (_)_ __ | | _\ \ / /__ / ___| |__ __ _| |_ / ___| __ _| |_ __\ \ / /_ _ _ _
| | | | '_ \| |/ /\ \ /\ / / _ \ | | '_ \ / _` | __| | _ / _` | __/ _ \ \ /\ / / _` | | | |
| |___| | | | | < \ V V / __/ |___| | | | (_| | |_| |_| | (_| | || __/\ V V / (_| | |_| |
|_____|_|_| |_|_|\_\ \_/\_/ \___|\____|_| |_|\__,_|\__|\____|\__,_|\__\___| \_/\_/ \__,_|\__, |
|___/
${AnsiColor.BRIGHT_WHITE}
Spring Boot Version: ${spring-boot.version}
Spring Application Name: ${spring.application.name}
\ No newline at end of file
yd-gateway/src/main/resources/bootstrap.yml
0 → 100644
View file @
243a95c0
spring
:
profiles
:
active
:
test
# active: '@spring.profiles.active@'
---
spring
:
profiles
:
dev
main
:
allow-bean-definition-overriding
:
true
allow-circular-references
:
true
cloud
:
nacos
:
# 配置中心
config
:
# 命名空间id(此处不用public,因public初始化的空间, id为空) 4e237601-cea8-414d-b7b9-d7adc8cbcf95
namespace
:
22f9d61e-9011-4d45-88cb-24f9857e3eec
# nacos的ip地址和端口 120.79.64.17:10848
server-addr
:
127.0.0.1:8848
# 这个就表示 在我们nacos命名空间id为 dev中 有一个data-id 为 demo-service.yml 的配置文件 读取这个里面的配置
file-extension
:
yml
config-retry-time
:
300000
# 共享配置, 可以把公共配置放在同个命名空间下,然后创建一个 common.yml 文件 ,里面可以放共用的配置
shared-configs[0]
:
dataId
:
linkwe-common.yml
refresh
:
true
# 发布到注册中心 (如果没有使用可以不配)
discovery
:
# 命名空间id(此处不用public,因public初始化的空间, id为空)
namespace
:
${spring.cloud.nacos.config.namespace}
# nacos的ip地址和端口
server-addr
:
${spring.cloud.nacos.config.server-addr}
---
spring
:
profiles
:
test
main
:
allow-bean-definition-overriding
:
true
allow-circular-references
:
true
web-application-type
:
reactive
# 强制使用响应式模式
cloud
:
nacos
:
# 配置中心
config
:
# 命名空间id(此处不用public,因public初始化的空间, id为空)
namespace
:
c1e4cbcf-d8b7-4da9-a75a-7b75890fc390
# nacos的ip地址和端口
server-addr
:
139.224.145.34:8848
# 这个就表示 在我们nacos命名空间id为 dev中 有一个data-id 为 demo-service.yml 的配置文件 读取这个里面的配置
file-extension
:
yml
config-retry-time
:
300000
# 共享配置, 可以把公共配置放在同个命名空间下,然后创建一个 common.yml 文件 ,里面可以放共用的配置
shared-configs[0]
:
dataId
:
yd-common.yml
group
:
YD_GROUP
refresh
:
true
extension-configs
:
# 扩展配置
-
data-id
:
yd-gateway.yml
group
:
YD_GROUP
refresh
:
true
# 发布到注册中心 (如果没有使用可以不配)
discovery
:
# 命名空间id(此处不用public,因public初始化的空间, id为空)
namespace
:
${spring.cloud.nacos.config.namespace}
# nacos的ip地址和端口
server-addr
:
${spring.cloud.nacos.config.server-addr}
group
:
YD_GROUP
---
spring
:
profiles
:
prod
main
:
allow-bean-definition-overriding
:
true
allow-circular-references
:
true
cloud
:
nacos
:
# 配置中心
config
:
# 命名空间id(此处不用public,因public初始化的空间, id为空)
namespace
:
ewscrm
# nacos的ip地址和端口
server-addr
:
127.0.0.1:8848
# 这个就表示 在我们nacos命名空间id为 dev中 有一个data-id 为 demo-service.yml 的配置文件 读取这个里面的配置
file-extension
:
yml
config-retry-time
:
300000
# 共享配置, 可以把公共配置放在同个命名空间下,然后创建一个 common.yml 文件 ,里面可以放共用的配置
shared-configs[0]
:
dataId
:
yd-common.yml
refresh
:
true
group
:
YD_GROUP
# 发布到注册中心 (如果没有使用可以不配)
discovery
:
# 命名空间id(此处不用public,因public初始化的空间, id为空)
namespace
:
${spring.cloud.nacos.config.namespace}
# nacos的ip地址和端口
server-addr
:
${spring.cloud.nacos.config.server-addr}
yd-gateway/target/maven-archiver/pom.properties
View file @
243a95c0
#Generated by Maven
#
Mon Jul 28 18:02:36
CST 2025
#
Fri Aug 22 10:56:47
CST 2025
version
=
1.0-SNAPSHOT
groupId
=
com.yd
artifactId
=
yd-gateway
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment