Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
有来开源组织
youlai-mall
提交
ec404738
Y
youlai-mall
项目概览
有来开源组织
/
youlai-mall
通知
8
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
Y
youlai-mall
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
ec404738
编写于
6月 29, 2023
作者:
郝
郝先瑞
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat: 新增SAS密码、验证码、短信验证码和微信小程序授权模式
上级
37a90229
变更
37
隐藏空白更改
内联
并排
Showing
37 changed file
with
868 addition
and
186 deletion
+868
-186
docs/nacos/nacos_config.zip
docs/nacos/nacos_config.zip
+0
-0
mall-oms/oms-boot/src/main/resources/bootstrap-prod.yml
mall-oms/oms-boot/src/main/resources/bootstrap-prod.yml
+2
-2
mall-pms/pms-boot/src/main/resources/bootstrap-prod.yml
mall-pms/pms-boot/src/main/resources/bootstrap-prod.yml
+2
-2
mall-sms/sms-boot/src/main/resources/bootstrap-prod.yml
mall-sms/sms-boot/src/main/resources/bootstrap-prod.yml
+2
-2
mall-ums/ums-boot/src/main/resources/bootstrap-prod.yml
mall-ums/ums-boot/src/main/resources/bootstrap-prod.yml
+2
-2
pom.xml
pom.xml
+7
-13
youlai-auth/pom.xml
youlai-auth/pom.xml
+5
-5
youlai-auth/src/main/java/com/youlai/auth/authentication/captcha/CaptchaAuthenticationConverter.java
...uthentication/captcha/CaptchaAuthenticationConverter.java
+115
-0
youlai-auth/src/main/java/com/youlai/auth/authentication/captcha/CaptchaAuthenticationProvider.java
...authentication/captcha/CaptchaAuthenticationProvider.java
+216
-0
youlai-auth/src/main/java/com/youlai/auth/authentication/captcha/CaptchaAuthenticationToken.java
...th/authentication/captcha/CaptchaAuthenticationToken.java
+62
-0
youlai-auth/src/main/java/com/youlai/auth/authentication/captcha/CaptchaParameterNames.java
...ai/auth/authentication/captcha/CaptchaParameterNames.java
+26
-0
youlai-auth/src/main/java/com/youlai/auth/authentication/password/PasswordAuthenticationConverter.java
...hentication/password/PasswordAuthenticationConverter.java
+4
-4
youlai-auth/src/main/java/com/youlai/auth/authentication/password/PasswordAuthenticationProvider.java
...thentication/password/PasswordAuthenticationProvider.java
+8
-8
youlai-auth/src/main/java/com/youlai/auth/authentication/password/PasswordAuthenticationToken.java
.../authentication/password/PasswordAuthenticationToken.java
+6
-4
youlai-auth/src/main/java/com/youlai/auth/authentication/smscode/SmsCodeAuthenticationConverter.java
...uthentication/smscode/SmsCodeAuthenticationConverter.java
+4
-4
youlai-auth/src/main/java/com/youlai/auth/authentication/smscode/SmsCodeAuthenticationProvider.java
...authentication/smscode/SmsCodeAuthenticationProvider.java
+9
-9
youlai-auth/src/main/java/com/youlai/auth/authentication/smscode/SmsCodeAuthenticationToken.java
...th/authentication/smscode/SmsCodeAuthenticationToken.java
+1
-1
youlai-auth/src/main/java/com/youlai/auth/authentication/smscode/SmsCodeParameterNames.java
...ai/auth/authentication/smscode/SmsCodeParameterNames.java
+41
-0
youlai-auth/src/main/java/com/youlai/auth/authentication/wxminiapp/WxMiniAppAuthenticationProvider.java
...entication/wxminiapp/WxMiniAppAuthenticationProvider.java
+6
-6
youlai-auth/src/main/java/com/youlai/auth/config/AuthorizationServerConfig.java
...ava/com/youlai/auth/config/AuthorizationServerConfig.java
+121
-26
youlai-auth/src/main/java/com/youlai/auth/config/SecurityConfig.java
.../src/main/java/com/youlai/auth/config/SecurityConfig.java
+2
-0
youlai-auth/src/main/java/com/youlai/auth/userdetails/member/MemberDetails.java
...ava/com/youlai/auth/userdetails/member/MemberDetails.java
+2
-4
youlai-auth/src/main/java/com/youlai/auth/userdetails/member/MemberDetailsService.java
.../youlai/auth/userdetails/member/MemberDetailsService.java
+30
-7
youlai-auth/src/main/java/com/youlai/auth/userdetails/member/MobileUserDetailsService.java
...lai/auth/userdetails/member/MobileUserDetailsService.java
+0
-61
youlai-auth/src/main/java/com/youlai/auth/userdetails/user/SysUserDetails.java
...java/com/youlai/auth/userdetails/user/SysUserDetails.java
+1
-3
youlai-auth/src/main/java/com/youlai/auth/userdetails/user/SysUserDetailsService.java
...m/youlai/auth/userdetails/user/SysUserDetailsService.java
+0
-1
youlai-auth/src/main/resources/bootstrap-dev.yml
youlai-auth/src/main/resources/bootstrap-dev.yml
+4
-2
youlai-auth/src/main/resources/bootstrap-prod.yml
youlai-auth/src/main/resources/bootstrap-prod.yml
+2
-3
youlai-auth/src/test/java/com/youlai/auth/authentication/CaptchaAuthenticationTests.java
...oulai/auth/authentication/CaptchaAuthenticationTests.java
+48
-0
youlai-auth/src/test/java/com/youlai/auth/authentication/PasswordAuthenticationTests.java
...ulai/auth/authentication/PasswordAuthenticationTests.java
+45
-0
youlai-auth/src/test/java/com/youlai/auth/authentication/SmsCodeAuthenticationTests.java
...oulai/auth/authentication/SmsCodeAuthenticationTests.java
+43
-0
youlai-auth/src/test/java/com/youlai/auth/authentication/WechatMiniAppAuthenticationTests.java
...auth/authentication/WechatMiniAppAuthenticationTests.java
+43
-0
youlai-gateway/src/main/java/com/youlai/gateway/captcha/handler/CaptchaHandler.java
...va/com/youlai/gateway/captcha/handler/CaptchaHandler.java
+1
-1
youlai-gateway/src/main/resources/bootstrap-prod.yml
youlai-gateway/src/main/resources/bootstrap-prod.yml
+3
-3
youlai-system/system-boot/src/main/java/com/youlai/system/controller/SysUserController.java
.../java/com/youlai/system/controller/SysUserController.java
+2
-7
youlai-system/system-boot/src/main/java/com/youlai/system/service/impl/SysUserServiceImpl.java
...va/com/youlai/system/service/impl/SysUserServiceImpl.java
+0
-3
youlai-system/system-boot/src/main/resources/bootstrap-prod.yml
...-system/system-boot/src/main/resources/bootstrap-prod.yml
+3
-3
未找到文件。
docs/nacos/nacos_config.zip
浏览文件 @
ec404738
无法预览此类型文件
mall-oms/oms-boot/src/main/resources/bootstrap-prod.yml
浏览文件 @
ec404738
...
...
@@ -11,11 +11,11 @@ spring:
nacos
:
discovery
:
server-addr
:
http://f.youlai.tech:8848
namespace
:
prod
-namespace-id
namespace
:
prod
config
:
server-addr
:
${spring.cloud.nacos.discovery.server-addr}
file-extension
:
yaml
namespace
:
prod
-namespace-id
namespace
:
prod
shared-configs[0]
:
data-id
:
youlai-common.yaml
refresh
:
true
...
...
mall-pms/pms-boot/src/main/resources/bootstrap-prod.yml
浏览文件 @
ec404738
...
...
@@ -11,11 +11,11 @@ spring:
nacos
:
discovery
:
server-addr
:
http://f.youlai.tech:8848
namespace
:
prod
-namespace-id
namespace
:
prod
config
:
server-addr
:
${spring.cloud.nacos.discovery.server-addr}
file-extension
:
yaml
namespace
:
prod
-namespace-id
namespace
:
prod
# 公共配置
shared-configs[0]
:
data-id
:
youlai-common.yaml
...
...
mall-sms/sms-boot/src/main/resources/bootstrap-prod.yml
浏览文件 @
ec404738
...
...
@@ -12,12 +12,12 @@ spring:
# 注册中心
discovery
:
server-addr
:
http://f.youlai.tech:8848
namespace
:
prod
-namespace-id
namespace
:
prod
# 配置中心
config
:
server-addr
:
${spring.cloud.nacos.discovery.server-addr}
file-extension
:
yaml
namespace
:
prod
-namespace-id
namespace
:
prod
shared-configs[0]
:
data-id
:
youlai-common.yaml
refresh
:
true
\ No newline at end of file
mall-ums/ums-boot/src/main/resources/bootstrap-prod.yml
浏览文件 @
ec404738
...
...
@@ -11,11 +11,11 @@ spring:
nacos
:
discovery
:
server-addr
:
http://f.youlai.tech:8848
namespace
:
prod
-namespace-id
namespace
:
prod
config
:
server-addr
:
${spring.cloud.nacos.discovery.server-addr}
file-extension
:
yaml
namespace
:
prod
-namespace-id
namespace
:
prod
shared-configs[0]
:
data-id
:
youlai-common.yaml
refresh
:
true
pom.xml
浏览文件 @
ec404738
...
...
@@ -35,14 +35,14 @@
<maven.compiler.source>
17
</maven.compiler.source>
<maven.compiler.target>
17
</maven.compiler.target>
<spring-boot.version>
3.1.
0
</spring-boot.version>
<spring-boot.version>
3.1.
1
</spring-boot.version>
<!-- spring cloud & alibaba -->
<spring-cloud.version>
2022.0.
3
</spring-cloud.version>
<spring-cloud.version>
2022.0.
2
</spring-cloud.version>
<spring-cloud-alibaba.version>
2022.0.0.0-RC2
</spring-cloud-alibaba.version>
<!-- spring authorization server -->
<
authorization-server.version>
1.1.0
</
authorization-server.version>
<nimbus-jose-jwt.version>
9.
16.
1
</nimbus-jose-jwt.version>
<
spring-authorization-server.version>
1.1.0
</spring-
authorization-server.version>
<nimbus-jose-jwt.version>
9.
3
1
</nimbus-jose-jwt.version>
<!-- db && orm -->
<mysql.version>
8.0.28
</mysql.version>
...
...
@@ -60,7 +60,7 @@
<easyexcel.version>
3.0.5
</easyexcel.version>
<easy-captcha.version>
1.6.2
</easy-captcha.version>
<nimbus-jose-jwt.version>
9.16.1
</nimbus-jose-jwt.version>
<thumbnailator.version>
0.4.1
7
</thumbnailator.version>
<thumbnailator.version>
0.4.1
9
</thumbnailator.version>
<!-- 阿里云短信 -->
<aliyun.java.sdk.core.version>
4.5.25
</aliyun.java.sdk.core.version>
...
...
@@ -69,7 +69,7 @@
<!-- minio -->
<minio.version>
8.5.3
</minio.version>
<okhttp3.version>
4.8.1
</okhttp3.version>
<!-- aliyun oss sdk -->
<aliyun-sdk-oss.version>
3.16.3
</aliyun-sdk-oss.version>
<!-- redisson 分布式锁 -->
...
...
@@ -302,16 +302,10 @@
<version>
${nimbus-jose-jwt.version}
</version>
</dependency>
<dependency>
<groupId>
net.coobird
</groupId>
<artifactId>
thumbnailator
</artifactId>
<version>
${thumbnailator.version}
</version>
</dependency>
<dependency>
<groupId>
org.springframework.security
</groupId>
<artifactId>
spring-security-oauth2-authorization-server
</artifactId>
<version>
${authorization-server.version}
</version>
<version>
${
spring-
authorization-server.version}
</version>
</dependency>
<dependency>
...
...
youlai-auth/pom.xml
浏览文件 @
ec404738
...
...
@@ -12,6 +12,11 @@
<artifactId>
youlai-auth
</artifactId>
<dependencies>
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-test
</artifactId>
<scope>
test
</scope>
</dependency>
<!--Spring Cloud & Alibaba -->
<dependency>
...
...
@@ -88,11 +93,6 @@
<artifactId>
common-mybatis
</artifactId>
</dependency>
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-test
</artifactId>
<scope>
test
</scope>
</dependency>
</dependencies>
<build>
...
...
youlai-auth/src/main/java/com/youlai/auth/authentication/captcha/CaptchaAuthenticationConverter.java
0 → 100644
浏览文件 @
ec404738
package
com.youlai.auth.authentication.captcha
;
import
cn.hutool.core.util.StrUtil
;
import
com.youlai.auth.util.OAuth2EndpointUtils
;
import
jakarta.servlet.http.HttpServletRequest
;
import
org.springframework.security.core.Authentication
;
import
org.springframework.security.core.context.SecurityContextHolder
;
import
org.springframework.security.oauth2.core.OAuth2ErrorCodes
;
import
org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames
;
import
org.springframework.security.web.authentication.AuthenticationConverter
;
import
org.springframework.util.MultiValueMap
;
import
org.springframework.util.StringUtils
;
import
java.util.Arrays
;
import
java.util.HashSet
;
import
java.util.Map
;
import
java.util.Set
;
import
java.util.stream.Collectors
;
/**
* 密码认证参数解析器
* <p>
* 解析请求参数中的用户名和密码,并构建相应的身份验证(Authentication)对象
*
* @author haoxr
* @since 3.0.0
*/
public
class
CaptchaAuthenticationConverter
implements
AuthenticationConverter
{
@Override
public
Authentication
convert
(
HttpServletRequest
request
)
{
// 授权类型 (必需)
String
grantType
=
request
.
getParameter
(
OAuth2ParameterNames
.
GRANT_TYPE
);
if
(!
CaptchaAuthenticationToken
.
CAPTCHA
.
getValue
().
equals
(
grantType
))
{
return
null
;
}
// 客户端信息
Authentication
clientPrincipal
=
SecurityContextHolder
.
getContext
().
getAuthentication
();
// 参数提取验证
MultiValueMap
<
String
,
String
>
parameters
=
OAuth2EndpointUtils
.
getParameters
(
request
);
// 令牌申请访问范围验证 (可选)
String
scope
=
parameters
.
getFirst
(
OAuth2ParameterNames
.
SCOPE
);
if
(
StringUtils
.
hasText
(
scope
)
&&
parameters
.
get
(
OAuth2ParameterNames
.
SCOPE
).
size
()
!=
1
)
{
OAuth2EndpointUtils
.
throwError
(
OAuth2ErrorCodes
.
INVALID_REQUEST
,
OAuth2ParameterNames
.
SCOPE
,
OAuth2EndpointUtils
.
ACCESS_TOKEN_REQUEST_ERROR_URI
);
}
Set
<
String
>
requestedScopes
=
null
;
if
(
StringUtils
.
hasText
(
scope
))
{
requestedScopes
=
new
HashSet
<>(
Arrays
.
asList
(
StringUtils
.
delimitedListToStringArray
(
scope
,
" "
)));
}
// 用户名验证(必需)
String
username
=
parameters
.
getFirst
(
OAuth2ParameterNames
.
USERNAME
);
if
(
StrUtil
.
isBlank
(
username
))
{
OAuth2EndpointUtils
.
throwError
(
OAuth2ErrorCodes
.
INVALID_REQUEST
,
OAuth2ParameterNames
.
USERNAME
,
OAuth2EndpointUtils
.
ACCESS_TOKEN_REQUEST_ERROR_URI
);
}
// 密码验证(必需)
String
password
=
parameters
.
getFirst
(
OAuth2ParameterNames
.
PASSWORD
);
if
(
StrUtil
.
isBlank
(
password
))
{
OAuth2EndpointUtils
.
throwError
(
OAuth2ErrorCodes
.
INVALID_REQUEST
,
OAuth2ParameterNames
.
PASSWORD
,
OAuth2EndpointUtils
.
ACCESS_TOKEN_REQUEST_ERROR_URI
);
}
// 验证码(必需)
String
verifyCode
=
parameters
.
getFirst
(
CaptchaParameterNames
.
VERIFY_CODE
);
if
(
StrUtil
.
isBlank
(
verifyCode
))
{
OAuth2EndpointUtils
.
throwError
(
OAuth2ErrorCodes
.
INVALID_REQUEST
,
CaptchaParameterNames
.
VERIFY_CODE
,
OAuth2EndpointUtils
.
ACCESS_TOKEN_REQUEST_ERROR_URI
);
}
// 验证码缓存Key(必需)
String
verifyCodeKey
=
parameters
.
getFirst
(
CaptchaParameterNames
.
VERIFY_CODE_KEY
);
if
(
StrUtil
.
isBlank
(
verifyCodeKey
))
{
OAuth2EndpointUtils
.
throwError
(
OAuth2ErrorCodes
.
INVALID_REQUEST
,
CaptchaParameterNames
.
VERIFY_CODE_KEY
,
OAuth2EndpointUtils
.
ACCESS_TOKEN_REQUEST_ERROR_URI
);
}
// 附加参数(保存用户名/密码传递给 CaptchaAuthenticationProvider 用于身份认证)
Map
<
String
,
Object
>
additionalParameters
=
parameters
.
entrySet
()
.
stream
()
.
filter
(
e
->
!
e
.
getKey
().
equals
(
OAuth2ParameterNames
.
GRANT_TYPE
)
&&
!
e
.
getKey
().
equals
(
OAuth2ParameterNames
.
SCOPE
)
).
collect
(
Collectors
.
toMap
(
Map
.
Entry
::
getKey
,
e
->
e
.
getValue
().
get
(
0
)));
return
new
CaptchaAuthenticationToken
(
clientPrincipal
,
requestedScopes
,
additionalParameters
);
}
}
youlai-auth/src/main/java/com/youlai/auth/authentication/captcha/CaptchaAuthenticationProvider.java
0 → 100644
浏览文件 @
ec404738
package
com.youlai.auth.authentication.captcha
;
import
cn.hutool.core.lang.Assert
;
import
cn.hutool.core.util.StrUtil
;
import
com.youlai.auth.authentication.smscode.SmsCodeParameterNames
;
import
com.youlai.auth.util.OAuth2AuthenticationProviderUtils
;
import
com.youlai.common.constant.SecurityConstants
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.data.redis.core.RedisTemplate
;
import
org.springframework.security.authentication.AuthenticationManager
;
import
org.springframework.security.authentication.AuthenticationProvider
;
import
org.springframework.security.authentication.UsernamePasswordAuthenticationToken
;
import
org.springframework.security.core.Authentication
;
import
org.springframework.security.core.AuthenticationException
;
import
org.springframework.security.oauth2.core.*
;
import
org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames
;
import
org.springframework.security.oauth2.core.oidc.OidcIdToken
;
import
org.springframework.security.oauth2.core.oidc.OidcScopes
;
import
org.springframework.security.oauth2.core.oidc.endpoint.OidcParameterNames
;
import
org.springframework.security.oauth2.jwt.Jwt
;
import
org.springframework.security.oauth2.server.authorization.OAuth2Authorization
;
import
org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService
;
import
org.springframework.security.oauth2.server.authorization.OAuth2TokenType
;
import
org.springframework.security.oauth2.server.authorization.authentication.OAuth2AccessTokenAuthenticationToken
;
import
org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken
;
import
org.springframework.security.oauth2.server.authorization.client.RegisteredClient
;
import
org.springframework.security.oauth2.server.authorization.context.AuthorizationServerContextHolder
;
import
org.springframework.security.oauth2.server.authorization.token.DefaultOAuth2TokenContext
;
import
org.springframework.security.oauth2.server.authorization.token.OAuth2TokenContext
;
import
org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator
;
import
org.springframework.util.CollectionUtils
;
import
java.security.Principal
;
import
java.util.*
;
import
java.util.stream.Collectors
;
/**
* 验证码模式身份验证提供者
* <p>
* 处理基于用户名和密码的身份验证
*
* @author haoxr
* @see org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationCodeAuthenticationProvider
* @since 3.0.0
*/
@Slf4j
public
class
CaptchaAuthenticationProvider
implements
AuthenticationProvider
{
private
static
final
String
ERROR_URI
=
"https://datatracker.ietf.org/doc/html/rfc6749#section-5.2"
;
private
static
final
OAuth2TokenType
ID_TOKEN_TOKEN_TYPE
=
new
OAuth2TokenType
(
OidcParameterNames
.
ID_TOKEN
);
private
final
AuthenticationManager
authenticationManager
;
private
final
OAuth2AuthorizationService
authorizationService
;
private
final
OAuth2TokenGenerator
<?
extends
OAuth2Token
>
tokenGenerator
;
private
final
RedisTemplate
redisTemplate
;
/**
* Constructs an {@code OAuth2ResourceOwnerPasswordAuthenticationProviderNew} using the provided parameters.
*
* @param authenticationManager the authentication manager
* @param authorizationService the authorization service
* @param tokenGenerator the token generator
* @since 0.2.3
*/
public
CaptchaAuthenticationProvider
(
AuthenticationManager
authenticationManager
,
OAuth2AuthorizationService
authorizationService
,
OAuth2TokenGenerator
<?
extends
OAuth2Token
>
tokenGenerator
,
RedisTemplate
redisTemplate
)
{
Assert
.
notNull
(
authorizationService
,
"authorizationService cannot be null"
);
Assert
.
notNull
(
tokenGenerator
,
"tokenGenerator cannot be null"
);
this
.
authenticationManager
=
authenticationManager
;
this
.
authorizationService
=
authorizationService
;
this
.
tokenGenerator
=
tokenGenerator
;
this
.
redisTemplate
=
redisTemplate
;
}
@Override
public
Authentication
authenticate
(
Authentication
authentication
)
throws
AuthenticationException
{
CaptchaAuthenticationToken
captchaAuthenticationToken
=
(
CaptchaAuthenticationToken
)
authentication
;
OAuth2ClientAuthenticationToken
clientPrincipal
=
OAuth2AuthenticationProviderUtils
.
getAuthenticatedClientElseThrowInvalidClient
(
captchaAuthenticationToken
);
RegisteredClient
registeredClient
=
clientPrincipal
.
getRegisteredClient
();
// 验证客户端是否支持授权类型(grant_type=password)
if
(!
registeredClient
.
getAuthorizationGrantTypes
().
contains
(
CaptchaAuthenticationToken
.
CAPTCHA
))
{
throw
new
OAuth2AuthenticationException
(
OAuth2ErrorCodes
.
UNAUTHORIZED_CLIENT
);
}
// 证码校验
Map
<
String
,
Object
>
additionalParameters
=
captchaAuthenticationToken
.
getAdditionalParameters
();
String
verifyCode
=
(
String
)
additionalParameters
.
get
(
CaptchaParameterNames
.
VERIFY_CODE
);
String
verifyCodeKey
=
(
String
)
additionalParameters
.
get
(
CaptchaParameterNames
.
VERIFY_CODE_KEY
);
String
cacheCode
=
(
String
)
redisTemplate
.
opsForValue
().
get
(
verifyCodeKey
);
if
(!
StrUtil
.
equals
(
verifyCode
,
cacheCode
))
{
throw
new
OAuth2AuthenticationException
(
"验证码错误"
);
}
// 生成用户名密码身份验证令牌
String
username
=
(
String
)
additionalParameters
.
get
(
OAuth2ParameterNames
.
USERNAME
);
String
password
=
(
String
)
additionalParameters
.
get
(
OAuth2ParameterNames
.
PASSWORD
);
UsernamePasswordAuthenticationToken
usernamePasswordAuthenticationToken
=
new
UsernamePasswordAuthenticationToken
(
username
,
password
);
// 用户名密码身份验证,成功后返回带有权限的认证信息
Authentication
usernamePasswordAuthentication
=
authenticationManager
.
authenticate
(
usernamePasswordAuthenticationToken
);
// 验证申请访问范围(Scope)
Set
<
String
>
authorizedScopes
=
registeredClient
.
getScopes
();
Set
<
String
>
requestedScopes
=
captchaAuthenticationToken
.
getScopes
();
if
(!
CollectionUtils
.
isEmpty
(
requestedScopes
))
{
Set
<
String
>
unauthorizedScopes
=
requestedScopes
.
stream
()
.
filter
(
requestedScope
->
!
registeredClient
.
getScopes
().
contains
(
requestedScope
))
.
collect
(
Collectors
.
toSet
());
if
(!
CollectionUtils
.
isEmpty
(
unauthorizedScopes
))
{
throw
new
OAuth2AuthenticationException
(
OAuth2ErrorCodes
.
INVALID_SCOPE
);
}
authorizedScopes
=
new
LinkedHashSet
<>(
requestedScopes
);
}
// 访问令牌(Access Token) 构造器
DefaultOAuth2TokenContext
.
Builder
tokenContextBuilder
=
DefaultOAuth2TokenContext
.
builder
()
.
registeredClient
(
registeredClient
)
.
principal
(
usernamePasswordAuthentication
)
// 身份验证成功的认证信息(用户名、权限等信息)
.
authorizationServerContext
(
AuthorizationServerContextHolder
.
getContext
())
.
authorizedScopes
(
authorizedScopes
)
.
authorizationGrantType
(
CaptchaAuthenticationToken
.
CAPTCHA
)
// 授权方式
.
authorizationGrant
(
captchaAuthenticationToken
)
// 授权具体对象
;
// 生成访问令牌(Access Token)
OAuth2TokenContext
tokenContext
=
tokenContextBuilder
.
tokenType
((
OAuth2TokenType
.
ACCESS_TOKEN
)).
build
();
OAuth2Token
generatedAccessToken
=
this
.
tokenGenerator
.
generate
(
tokenContext
);
if
(
generatedAccessToken
==
null
)
{
OAuth2Error
error
=
new
OAuth2Error
(
OAuth2ErrorCodes
.
SERVER_ERROR
,
"The token generator failed to generate the access token."
,
ERROR_URI
);
throw
new
OAuth2AuthenticationException
(
error
);
}
OAuth2AccessToken
accessToken
=
new
OAuth2AccessToken
(
OAuth2AccessToken
.
TokenType
.
BEARER
,
generatedAccessToken
.
getTokenValue
(),
generatedAccessToken
.
getIssuedAt
(),
generatedAccessToken
.
getExpiresAt
(),
tokenContext
.
getAuthorizedScopes
());
OAuth2Authorization
.
Builder
authorizationBuilder
=
OAuth2Authorization
.
withRegisteredClient
(
registeredClient
)
.
principalName
(
usernamePasswordAuthentication
.
getName
())
.
authorizationGrantType
(
CaptchaAuthenticationToken
.
CAPTCHA
)
.
authorizedScopes
(
authorizedScopes
)
.
attribute
(
Principal
.
class
.
getName
(),
usernamePasswordAuthentication
);
if
(
generatedAccessToken
instanceof
ClaimAccessor
)
{
authorizationBuilder
.
token
(
accessToken
,
(
metadata
)
->
metadata
.
put
(
OAuth2Authorization
.
Token
.
CLAIMS_METADATA_NAME
,
((
ClaimAccessor
)
generatedAccessToken
).
getClaims
()));
}
else
{
authorizationBuilder
.
accessToken
(
accessToken
);
}
// 生成刷新令牌(Refresh Token)
OAuth2RefreshToken
refreshToken
=
null
;
if
(
registeredClient
.
getAuthorizationGrantTypes
().
contains
(
AuthorizationGrantType
.
REFRESH_TOKEN
)
&&
// Do not issue refresh token to public client
!
clientPrincipal
.
getClientAuthenticationMethod
().
equals
(
ClientAuthenticationMethod
.
NONE
))
{
tokenContext
=
tokenContextBuilder
.
tokenType
(
OAuth2TokenType
.
REFRESH_TOKEN
).
build
();
OAuth2Token
generatedRefreshToken
=
this
.
tokenGenerator
.
generate
(
tokenContext
);
if
(!(
generatedRefreshToken
instanceof
OAuth2RefreshToken
))
{
OAuth2Error
error
=
new
OAuth2Error
(
OAuth2ErrorCodes
.
SERVER_ERROR
,
"The token generator failed to generate the refresh token."
,
ERROR_URI
);
throw
new
OAuth2AuthenticationException
(
error
);
}
refreshToken
=
(
OAuth2RefreshToken
)
generatedRefreshToken
;
authorizationBuilder
.
refreshToken
(
refreshToken
);
}
// 生成 ID token
OidcIdToken
idToken
;
if
(
requestedScopes
.
contains
(
OidcScopes
.
OPENID
))
{
// @formatter:off
tokenContext
=
tokenContextBuilder
.
tokenType
(
ID_TOKEN_TOKEN_TYPE
)
.
authorization
(
authorizationBuilder
.
build
())
// ID token customizer may need access to the access token and/or refresh token
.
build
();
// @formatter:on
OAuth2Token
generatedIdToken
=
this
.
tokenGenerator
.
generate
(
tokenContext
);
if
(!(
generatedIdToken
instanceof
Jwt
))
{
OAuth2Error
error
=
new
OAuth2Error
(
OAuth2ErrorCodes
.
SERVER_ERROR
,
"The token generator failed to generate the ID token."
,
ERROR_URI
);
throw
new
OAuth2AuthenticationException
(
error
);
}
idToken
=
new
OidcIdToken
(
generatedIdToken
.
getTokenValue
(),
generatedIdToken
.
getIssuedAt
(),
generatedIdToken
.
getExpiresAt
(),
((
Jwt
)
generatedIdToken
).
getClaims
());
authorizationBuilder
.
token
(
idToken
,
(
metadata
)
->
metadata
.
put
(
OAuth2Authorization
.
Token
.
CLAIMS_METADATA_NAME
,
idToken
.
getClaims
()));
}
else
{
idToken
=
null
;
}
OAuth2Authorization
authorization
=
authorizationBuilder
.
build
();
this
.
authorizationService
.
save
(
authorization
);
additionalParameters
=
Collections
.
emptyMap
();
if
(
idToken
!=
null
)
{
additionalParameters
=
new
HashMap
<>();
additionalParameters
.
put
(
OidcParameterNames
.
ID_TOKEN
,
idToken
.
getTokenValue
());
}
return
new
OAuth2AccessTokenAuthenticationToken
(
registeredClient
,
clientPrincipal
,
accessToken
,
refreshToken
,
additionalParameters
);
}
@Override
public
boolean
supports
(
Class
<?>
authentication
)
{
return
CaptchaAuthenticationToken
.
class
.
isAssignableFrom
(
authentication
);
}
}
youlai-auth/src/main/java/com/youlai/auth/authentication/captcha/CaptchaAuthenticationToken.java
0 → 100644
浏览文件 @
ec404738
package
com.youlai.auth.authentication.captcha
;
import
jakarta.annotation.Nullable
;
import
org.springframework.security.core.Authentication
;
import
org.springframework.security.oauth2.core.AuthorizationGrantType
;
import
org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames
;
import
org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationGrantAuthenticationToken
;
import
java.util.Collections
;
import
java.util.HashSet
;
import
java.util.Map
;
import
java.util.Set
;
/**
* 验证码模式身份验证令牌(包含用户名、密码、验证码)
*
* @author haoxr
* @see org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientCredentialsAuthenticationToken
* @since 3.0.0
*/
public
class
CaptchaAuthenticationToken
extends
OAuth2AuthorizationGrantAuthenticationToken
{
/**
* 令牌申请访问范围
*/
private
final
Set
<
String
>
scopes
;
/**
* 授权类型(验证码: captcha)
*/
public
static
final
AuthorizationGrantType
CAPTCHA
=
new
AuthorizationGrantType
(
"captcha"
);
/**
* 验证码模式身份验证令牌
*
* @param clientPrincipal 客户端信息
* @param scopes 令牌申请访问范围
* @param additionalParameters 自定义额外参数(用户名、密码、验证码)
*/
public
CaptchaAuthenticationToken
(
Authentication
clientPrincipal
,
Set
<
String
>
scopes
,
@Nullable
Map
<
String
,
Object
>
additionalParameters
)
{
super
(
CAPTCHA
,
clientPrincipal
,
additionalParameters
);
this
.
scopes
=
Collections
.
unmodifiableSet
(
scopes
!=
null
?
new
HashSet
<>(
scopes
)
:
Collections
.
emptySet
());
}
/**
* 用户凭证(密码)
*/
@Override
public
Object
getCredentials
()
{
return
this
.
getAdditionalParameters
().
get
(
OAuth2ParameterNames
.
PASSWORD
);
}
public
Set
<
String
>
getScopes
()
{
return
scopes
;
}
}
youlai-auth/src/main/java/com/youlai/auth/authentication/captcha/CaptchaParameterNames.java
0 → 100644
浏览文件 @
ec404738
package
com.youlai.auth.authentication.captcha
;
/**
* 验证码模式请求参数名称常量
*
* @author haoxr
* @since 3.0.0
*/
public
final
class
CaptchaParameterNames
{
/**
* 验证码
*/
public
static
final
String
VERIFY_CODE
=
"verifyCode"
;
/**
* 验证码缓存Key
*/
public
static
final
String
VERIFY_CODE_KEY
=
"verifyCodeKey"
;
private
CaptchaParameterNames
()
{
}
}
youlai-auth/src/main/java/com/youlai/auth/authentication/password/
ResourceOwner
PasswordAuthenticationConverter.java
→
youlai-auth/src/main/java/com/youlai/auth/authentication/password/PasswordAuthenticationConverter.java
浏览文件 @
ec404738
...
...
@@ -20,7 +20,7 @@ import java.util.Set;
import
java.util.stream.Collectors
;
/**
* 密码
认证
参数解析器
* 密码
模式
参数解析器
* <p>
* 解析请求参数中的用户名和密码,并构建相应的身份验证(Authentication)对象
*
...
...
@@ -28,7 +28,7 @@ import java.util.stream.Collectors;
* @see org.springframework.security.oauth2.server.authorization.web.authentication.OAuth2AuthorizationCodeAuthenticationConverter
* @since 3.0.0
*/
public
class
ResourceOwner
PasswordAuthenticationConverter
implements
AuthenticationConverter
{
public
class
PasswordAuthenticationConverter
implements
AuthenticationConverter
{
@Override
public
Authentication
convert
(
HttpServletRequest
request
)
{
...
...
@@ -78,7 +78,7 @@ public class ResourceOwnerPasswordAuthenticationConverter implements Authenticat
);
}
// 附加参数(保存用户名/密码传递给
ResourceOwner
PasswordAuthenticationProvider 用于身份认证)
// 附加参数(保存用户名/密码传递给 PasswordAuthenticationProvider 用于身份认证)
Map
<
String
,
Object
>
additionalParameters
=
parameters
.
entrySet
()
.
stream
()
...
...
@@ -86,7 +86,7 @@ public class ResourceOwnerPasswordAuthenticationConverter implements Authenticat
!
e
.
getKey
().
equals
(
OAuth2ParameterNames
.
SCOPE
)
).
collect
(
Collectors
.
toMap
(
Map
.
Entry
::
getKey
,
e
->
e
.
getValue
().
get
(
0
)));
return
new
ResourceOwner
PasswordAuthenticationToken
(
return
new
PasswordAuthenticationToken
(
clientPrincipal
,
requestedScopes
,
additionalParameters
...
...
youlai-auth/src/main/java/com/youlai/auth/authentication/password/
ResourceOwner
PasswordAuthenticationProvider.java
→
youlai-auth/src/main/java/com/youlai/auth/authentication/password/PasswordAuthenticationProvider.java
浏览文件 @
ec404738
package
com.youlai.auth.authentication.password
;
import
cn.hutool.core.lang.Assert
;
import
com.youlai.auth.util.OAuth2AuthenticationProviderUtils
;
import
lombok.extern.slf4j.Slf4j
;
...
...
@@ -36,11 +37,10 @@ import java.util.stream.Collectors;
* 处理基于用户名和密码的身份验证
*
* @author haoxr
* @see org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationCodeAuthenticationProvider
* @since 3.0.0
*/
@Slf4j
public
class
ResourceOwner
PasswordAuthenticationProvider
implements
AuthenticationProvider
{
public
class
PasswordAuthenticationProvider
implements
AuthenticationProvider
{
private
static
final
String
ERROR_URI
=
"https://datatracker.ietf.org/doc/html/rfc6749#section-5.2"
;
...
...
@@ -58,9 +58,9 @@ public class ResourceOwnerPasswordAuthenticationProvider implements Authenticati
* @param tokenGenerator the token generator
* @since 0.2.3
*/
public
ResourceOwner
PasswordAuthenticationProvider
(
AuthenticationManager
authenticationManager
,
OAuth2AuthorizationService
authorizationService
,
OAuth2TokenGenerator
<?
extends
OAuth2Token
>
tokenGenerator
public
PasswordAuthenticationProvider
(
AuthenticationManager
authenticationManager
,
OAuth2AuthorizationService
authorizationService
,
OAuth2TokenGenerator
<?
extends
OAuth2Token
>
tokenGenerator
)
{
Assert
.
notNull
(
authorizationService
,
"authorizationService cannot be null"
);
Assert
.
notNull
(
tokenGenerator
,
"tokenGenerator cannot be null"
);
...
...
@@ -72,7 +72,7 @@ public class ResourceOwnerPasswordAuthenticationProvider implements Authenticati
@Override
public
Authentication
authenticate
(
Authentication
authentication
)
throws
AuthenticationException
{
ResourceOwnerPasswordAuthenticationToken
resourceOwnerPasswordAuthentication
=
(
ResourceOwner
PasswordAuthenticationToken
)
authentication
;
PasswordAuthenticationToken
resourceOwnerPasswordAuthentication
=
(
PasswordAuthenticationToken
)
authentication
;
OAuth2ClientAuthenticationToken
clientPrincipal
=
OAuth2AuthenticationProviderUtils
.
getAuthenticatedClientElseThrowInvalidClient
(
resourceOwnerPasswordAuthentication
);
RegisteredClient
registeredClient
=
clientPrincipal
.
getRegisteredClient
();
...
...
@@ -138,7 +138,7 @@ public class ResourceOwnerPasswordAuthenticationProvider implements Authenticati
authorizationBuilder
.
accessToken
(
accessToken
);
}
// 生成刷新令牌(Refresh
t
oken)
// 生成刷新令牌(Refresh
T
oken)
OAuth2RefreshToken
refreshToken
=
null
;
if
(
registeredClient
.
getAuthorizationGrantTypes
().
contains
(
AuthorizationGrantType
.
REFRESH_TOKEN
)
&&
// Do not issue refresh token to public client
...
...
@@ -194,7 +194,7 @@ public class ResourceOwnerPasswordAuthenticationProvider implements Authenticati
@Override
public
boolean
supports
(
Class
<?>
authentication
)
{
return
ResourceOwner
PasswordAuthenticationToken
.
class
.
isAssignableFrom
(
authentication
);
return
PasswordAuthenticationToken
.
class
.
isAssignableFrom
(
authentication
);
}
}
youlai-auth/src/main/java/com/youlai/auth/authentication/password/
ResourceOwner
PasswordAuthenticationToken.java
→
youlai-auth/src/main/java/com/youlai/auth/authentication/password/PasswordAuthenticationToken.java
浏览文件 @
ec404738
...
...
@@ -12,10 +12,12 @@ import java.util.*;
* 密码授权模式身份验证令牌(包含用户名和密码等)
*
* @author haoxr
* @see org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientCredentialsAuthenticationToken
* @since 3.0.0
*/
public
class
ResourceOwnerPasswordAuthenticationToken
extends
OAuth2AuthorizationGrantAuthenticationToken
{
public
class
PasswordAuthenticationToken
extends
OAuth2AuthorizationGrantAuthenticationToken
{
public
static
final
AuthorizationGrantType
PASSWORD
=
new
AuthorizationGrantType
(
"password"
);
/**
* 令牌申请访问范围
...
...
@@ -29,12 +31,12 @@ public class ResourceOwnerPasswordAuthenticationToken extends OAuth2Authorizatio
* @param scopes 令牌申请访问范围
* @param additionalParameters 自定义额外参数(用户名和密码)
*/
public
ResourceOwner
PasswordAuthenticationToken
(
public
PasswordAuthenticationToken
(
Authentication
clientPrincipal
,
Set
<
String
>
scopes
,
@Nullable
Map
<
String
,
Object
>
additionalParameters
)
{
super
(
AuthorizationGrantType
.
PASSWORD
,
clientPrincipal
,
additionalParameters
);
super
(
PASSWORD
,
clientPrincipal
,
additionalParameters
);
this
.
scopes
=
Collections
.
unmodifiableSet
(
scopes
!=
null
?
new
HashSet
<>(
scopes
)
:
Collections
.
emptySet
());
}
...
...
youlai-auth/src/main/java/com/youlai/auth/authentication/smscode/SmsCodeAuthenticationConverter.java
浏览文件 @
ec404738
...
...
@@ -57,20 +57,20 @@ public class SmsCodeAuthenticationConverter implements AuthenticationConverter {
}
// 手机号(必需)
String
mobile
=
parameters
.
getFirst
(
"mobile"
);
String
mobile
=
parameters
.
getFirst
(
SmsCodeParameterNames
.
MOBILE
);
if
(
StrUtil
.
isBlank
(
mobile
))
{
OAuth2EndpointUtils
.
throwError
(
OAuth2ErrorCodes
.
INVALID_REQUEST
,
"mobile"
,
SmsCodeParameterNames
.
MOBILE
,
OAuth2EndpointUtils
.
ACCESS_TOKEN_REQUEST_ERROR_URI
);
}
// 验证码(必需)
String
verifyCode
=
parameters
.
getFirst
(
"verifyCode"
);
String
verifyCode
=
parameters
.
getFirst
(
SmsCodeParameterNames
.
VERIFY_CODE
);
if
(
StrUtil
.
isBlank
(
verifyCode
))
{
OAuth2EndpointUtils
.
throwError
(
OAuth2ErrorCodes
.
INVALID_REQUEST
,
"verifyCode"
,
SmsCodeParameterNames
.
VERIFY_CODE
,
OAuth2EndpointUtils
.
ACCESS_TOKEN_REQUEST_ERROR_URI
);
}
...
...
youlai-auth/src/main/java/com/youlai/auth/authentication/smscode/SmsCodeAuthenticationProvider.java
浏览文件 @
ec404738
...
...
@@ -2,7 +2,7 @@ package com.youlai.auth.authentication.smscode;
import
cn.hutool.core.lang.Assert
;
import
cn.hutool.core.util.StrUtil
;
import
com.youlai.auth.userdetails.member.M
obileUs
erDetailsService
;
import
com.youlai.auth.userdetails.member.M
emb
erDetailsService
;
import
com.youlai.auth.util.OAuth2AuthenticationProviderUtils
;
import
com.youlai.common.constant.SecurityConstants
;
import
lombok.extern.slf4j.Slf4j
;
...
...
@@ -41,7 +41,7 @@ public class SmsCodeAuthenticationProvider implements AuthenticationProvider {
private
final
OAuth2AuthorizationService
authorizationService
;
private
final
OAuth2TokenGenerator
<?
extends
OAuth2Token
>
tokenGenerator
;
private
final
M
obileUserDetailsService
mobileUs
erDetailsService
;
private
final
M
emberDetailsService
memb
erDetailsService
;
private
final
RedisTemplate
redisTemplate
;
...
...
@@ -55,17 +55,17 @@ public class SmsCodeAuthenticationProvider implements AuthenticationProvider {
public
SmsCodeAuthenticationProvider
(
OAuth2AuthorizationService
authorizationService
,
OAuth2TokenGenerator
<?
extends
OAuth2Token
>
tokenGenerator
,
M
obileUserDetailsService
mobileUs
erDetailsService
,
M
emberDetailsService
memb
erDetailsService
,
RedisTemplate
redisTemplate
)
{
Assert
.
notNull
(
authorizationService
,
"authorizationService cannot be null"
);
Assert
.
notNull
(
tokenGenerator
,
"tokenGenerator cannot be null"
);
Assert
.
notNull
(
m
obileUs
erDetailsService
,
"userDetailsService cannot be null"
);
Assert
.
notNull
(
m
emb
erDetailsService
,
"userDetailsService cannot be null"
);
Assert
.
notNull
(
redisTemplate
,
"redisTemplate cannot be null"
);
this
.
authorizationService
=
authorizationService
;
this
.
tokenGenerator
=
tokenGenerator
;
this
.
m
obileUserDetailsService
=
mobileUs
erDetailsService
;
this
.
m
emberDetailsService
=
memb
erDetailsService
;
this
.
redisTemplate
=
redisTemplate
;
}
...
...
@@ -83,10 +83,10 @@ public class SmsCodeAuthenticationProvider implements AuthenticationProvider {
throw
new
OAuth2AuthenticationException
(
OAuth2ErrorCodes
.
UNAUTHORIZED_CLIENT
);
}
//
微信 code 获取 openid
//
短信验证码校验
Map
<
String
,
Object
>
additionalParameters
=
smsCodeAuthenticationToken
.
getAdditionalParameters
();
String
mobile
=
(
String
)
additionalParameters
.
get
(
"mobile"
);
String
verifyCode
=
(
String
)
additionalParameters
.
get
(
"verifyCode"
);
String
mobile
=
(
String
)
additionalParameters
.
get
(
SmsCodeParameterNames
.
MOBILE
);
String
verifyCode
=
(
String
)
additionalParameters
.
get
(
SmsCodeParameterNames
.
VERIFY_CODE
);
if
(!
verifyCode
.
equals
(
"666666"
))
{
// 666666 是后门,因为短信收费,正式环境删除这个if
String
codeKey
=
SecurityConstants
.
SMS_CODE_PREFIX
+
mobile
;
...
...
@@ -98,7 +98,7 @@ public class SmsCodeAuthenticationProvider implements AuthenticationProvider {
}
// 根据手机号获取会员信息
UserDetails
userDetails
=
m
obileUserDetailsService
.
loadUserByUsernam
e
(
mobile
);
UserDetails
userDetails
=
m
emberDetailsService
.
loadUserByMobil
e
(
mobile
);
Authentication
usernamePasswordAuthentication
=
new
UsernamePasswordAuthenticationToken
(
userDetails
,
null
);
...
...
youlai-auth/src/main/java/com/youlai/auth/authentication/smscode/SmsCodeAuthenticationToken.java
浏览文件 @
ec404738
...
...
@@ -25,7 +25,7 @@ public class SmsCodeAuthenticationToken extends OAuth2AuthorizationGrantAuthenti
private
final
Set
<
String
>
scopes
;
/**
* 授权类型(短信验证码
:
sms_code)
* 授权类型(短信验证码
:
sms_code)
*/
public
static
final
AuthorizationGrantType
SMS_CODE
=
new
AuthorizationGrantType
(
"sms_code"
);
...
...
youlai-auth/src/main/java/com/youlai/auth/authentication/smscode/SmsCodeParameterNames.java
0 → 100644
浏览文件 @
ec404738
/*
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com.youlai.auth.authentication.smscode
;
/**
* 短信验证码模式参数名称常量
*
* @author haoxr
* @since 3.0.0
*/
public
final
class
SmsCodeParameterNames
{
/**
* 手机号
*/
public
static
final
String
MOBILE
=
"mobile"
;
/**
* 验证码
*/
public
static
final
String
VERIFY_CODE
=
"verifyCode"
;
private
SmsCodeParameterNames
()
{
}
}
youlai-auth/src/main/java/com/youlai/auth/authentication/wxminiapp/WxMiniAppAuthenticationProvider.java
浏览文件 @
ec404738
...
...
@@ -3,7 +3,7 @@ package com.youlai.auth.authentication.wxminiapp;
import
cn.binarywang.wx.miniapp.api.WxMaService
;
import
cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult
;
import
cn.hutool.core.lang.Assert
;
import
com.youlai.auth.userdetails.member.
OpenidUs
erDetailsService
;
import
com.youlai.auth.userdetails.member.
Memb
erDetailsService
;
import
com.youlai.auth.util.OAuth2AuthenticationProviderUtils
;
import
lombok.extern.slf4j.Slf4j
;
import
me.chanjar.weixin.common.error.WxErrorException
;
...
...
@@ -42,7 +42,7 @@ public class WxMiniAppAuthenticationProvider implements AuthenticationProvider {
private
final
OAuth2AuthorizationService
authorizationService
;
private
final
OAuth2TokenGenerator
<?
extends
OAuth2Token
>
tokenGenerator
;
private
final
OpenidUserDetailsService
openidUs
erDetailsService
;
private
final
MemberDetailsService
memb
erDetailsService
;
private
final
WxMaService
wxMaService
;
...
...
@@ -57,17 +57,17 @@ public class WxMiniAppAuthenticationProvider implements AuthenticationProvider {
public
WxMiniAppAuthenticationProvider
(
OAuth2AuthorizationService
authorizationService
,
OAuth2TokenGenerator
<?
extends
OAuth2Token
>
tokenGenerator
,
OpenidUserDetailsService
openidUs
erDetailsService
,
MemberDetailsService
memb
erDetailsService
,
WxMaService
wxMaService
)
{
Assert
.
notNull
(
authorizationService
,
"authorizationService cannot be null"
);
Assert
.
notNull
(
tokenGenerator
,
"tokenGenerator cannot be null"
);
Assert
.
notNull
(
openidUs
erDetailsService
,
"userDetailsService cannot be null"
);
Assert
.
notNull
(
memb
erDetailsService
,
"userDetailsService cannot be null"
);
Assert
.
notNull
(
wxMaService
,
"wxMaService cannot be null"
);
this
.
authorizationService
=
authorizationService
;
this
.
tokenGenerator
=
tokenGenerator
;
this
.
openidUserDetailsService
=
openidUs
erDetailsService
;
this
.
memberDetailsService
=
memb
erDetailsService
;
this
.
wxMaService
=
wxMaService
;
}
...
...
@@ -97,7 +97,7 @@ public class WxMiniAppAuthenticationProvider implements AuthenticationProvider {
}
String
openid
=
sessionInfo
.
getOpenid
();
// 根据 openid 获取会员信息
UserDetails
userDetails
=
openidUserDetailsService
.
loadUserByUsername
(
openid
);
UserDetails
userDetails
=
memberDetailsService
.
loadUserByOpenid
(
openid
);
Authentication
usernamePasswordAuthentication
=
new
UsernamePasswordAuthenticationToken
(
userDetails
,
userDetails
.
getPassword
());
...
...
youlai-auth/src/main/java/com/youlai/auth/config/AuthorizationServerConfig.java
浏览文件 @
ec404738
...
...
@@ -7,15 +7,19 @@ import com.nimbusds.jose.jwk.RSAKey;
import
com.nimbusds.jose.jwk.source.ImmutableJWKSet
;
import
com.nimbusds.jose.jwk.source.JWKSource
;
import
com.nimbusds.jose.proc.SecurityContext
;
import
com.youlai.auth.authentication.password.ResourceOwnerPasswordAuthenticationConverter
;
import
com.youlai.auth.authentication.password.ResourceOwnerPasswordAuthenticationProvider
;
import
com.youlai.auth.authentication.captcha.CaptchaAuthenticationConverter
;
import
com.youlai.auth.authentication.captcha.CaptchaAuthenticationProvider
;
import
com.youlai.auth.authentication.captcha.CaptchaAuthenticationToken
;
import
com.youlai.auth.authentication.password.PasswordAuthenticationConverter
;
import
com.youlai.auth.authentication.password.PasswordAuthenticationProvider
;
import
com.youlai.auth.authentication.smscode.SmsCodeAuthenticationConverter
;
import
com.youlai.auth.authentication.smscode.SmsCodeAuthenticationProvider
;
import
com.youlai.auth.authentication.smscode.SmsCodeAuthenticationToken
;
import
com.youlai.auth.authentication.wxminiapp.WxMiniAppAuthenticationConverter
;
import
com.youlai.auth.authentication.wxminiapp.WxMiniAppAuthenticationProvider
;
import
com.youlai.auth.
userdetails.member.MemberUserDetails
;
import
com.youlai.auth.userdetails.member.M
obileUserDetailsService
;
import
com.youlai.auth.userdetails.member.
OpenidUs
erDetailsService
;
import
com.youlai.auth.
authentication.wxminiapp.WxMiniAppAuthenticationToken
;
import
com.youlai.auth.userdetails.member.M
emberDetails
;
import
com.youlai.auth.userdetails.member.
Memb
erDetailsService
;
import
com.youlai.auth.userdetails.user.SysUserDetails
;
import
lombok.RequiredArgsConstructor
;
import
org.springframework.context.annotation.Bean
;
...
...
@@ -30,16 +34,21 @@ import org.springframework.security.config.annotation.authentication.configurati
import
org.springframework.security.config.annotation.web.builders.HttpSecurity
;
import
org.springframework.security.crypto.factory.PasswordEncoderFactories
;
import
org.springframework.security.crypto.password.PasswordEncoder
;
import
org.springframework.security.oauth2.core.AuthorizationGrantType
;
import
org.springframework.security.oauth2.core.ClientAuthenticationMethod
;
import
org.springframework.security.oauth2.core.oidc.OidcScopes
;
import
org.springframework.security.oauth2.core.oidc.endpoint.OidcParameterNames
;
import
org.springframework.security.oauth2.jwt.JwtClaimsSet
;
import
org.springframework.security.oauth2.jwt.JwtDecoder
;
import
org.springframework.security.oauth2.jwt.NimbusJwtEncoder
;
import
org.springframework.security.oauth2.server.authorization.*
;
import
org.springframework.security.oauth2.server.authorization.client.JdbcRegisteredClientRepository
;
import
org.springframework.security.oauth2.server.authorization.client.RegisteredClient
;
import
org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository
;
import
org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration
;
import
org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer
;
import
org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings
;
import
org.springframework.security.oauth2.server.authorization.settings.ClientSettings
;
import
org.springframework.security.oauth2.server.authorization.token.*
;
import
org.springframework.security.web.SecurityFilterChain
;
import
org.springframework.security.web.util.matcher.RequestMatcher
;
...
...
@@ -52,14 +61,19 @@ import java.util.List;
import
java.util.Optional
;
import
java.util.UUID
;
/**
* 授权服务器配置
*
* @author haoxr
* @since 3.0.0
*/
@Configuration
@RequiredArgsConstructor
public
class
AuthorizationServerConfig
{
private
final
WxMaService
wxMaService
;
private
final
MobileUserDetailsService
mobileUserDetailsService
;
private
final
OpenidUserDetailsService
openidUserDetailsService
;
private
final
RedisTemplate
redisTemplate
;
private
final
MemberDetailsService
memberDetailsService
;
/**
...
...
@@ -80,25 +94,25 @@ public class AuthorizationServerConfig {
authorizationServerConfigurer
.
tokenEndpoint
(
tokenEndpoint
->
tokenEndpoint
.
accessTokenRequestConverters
(
// <1>
authenticationConverters
->
authenticationConverters
.
addAll
(
List
.
of
(
new
ResourceOwnerPasswordAuthenticationConverter
(),
new
WxMiniAppAuthenticationConverter
(),
new
SmsCodeAuthenticationConverter
()
)
.
accessTokenRequestConverters
(
authenticationConverters
->
// <1>
authenticationConverters
.
addAll
(
List
.
of
(
new
PasswordAuthenticationConverter
(),
new
CaptchaAuthenticationConverter
(),
new
WxMiniAppAuthenticationConverter
(),
new
SmsCodeAuthenticationConverter
()
)
)
)
.
authenticationProviders
(
// <2>
authenticationProviders
->
authenticationProviders
.
addAll
(
.
authenticationProviders
(
authenticationProviders
->
// <2>
authenticationProviders
.
addAll
(
List
.
of
(
new
ResourceOwnerPasswordAuthenticationProvider
(
authenticationManager
,
authorizationService
,
tokenGenerator
),
new
WxMiniAppAuthenticationProvider
(
authorizationService
,
tokenGenerator
,
openidUserDetailsService
,
wxMaService
),
new
SmsCodeAuthenticationProvider
(
authorizationService
,
tokenGenerator
,
mobileUserDetailsService
,
redisTemplate
)
new
PasswordAuthenticationProvider
(
authenticationManager
,
authorizationService
,
tokenGenerator
),
new
CaptchaAuthenticationProvider
(
authenticationManager
,
authorizationService
,
tokenGenerator
,
redisTemplate
),
new
WxMiniAppAuthenticationProvider
(
authorizationService
,
tokenGenerator
,
memberDetailsService
,
wxMaService
),
new
SmsCodeAuthenticationProvider
(
authorizationService
,
tokenGenerator
,
memberDetailsService
,
redisTemplate
)
)
)
)
)
);
...
...
@@ -161,9 +175,16 @@ public class AuthorizationServerConfig {
@Bean
public
RegisteredClientRepository
registeredClientRepository
(
JdbcTemplate
jdbcTemplate
)
{
return
new
JdbcRegisteredClientRepository
(
jdbcTemplate
);
JdbcRegisteredClientRepository
registeredClientRepository
=
new
JdbcRegisteredClientRepository
(
jdbcTemplate
);
// 初始化 OAuth2 客户端
initMallAppClient
(
registeredClientRepository
);
initMallAdminClient
(
registeredClientRepository
);
return
registeredClientRepository
;
}
@Bean
public
OAuth2AuthorizationService
authorizationService
(
JdbcTemplate
jdbcTemplate
,
RegisteredClientRepository
registeredClientRepository
)
{
...
...
@@ -178,7 +199,6 @@ public class AuthorizationServerConfig {
}
@Bean
OAuth2TokenGenerator
<?>
tokenGenerator
(
JWKSource
<
SecurityContext
>
jwkSource
)
{
JwtGenerator
jwtGenerator
=
new
JwtGenerator
(
new
NimbusJwtEncoder
(
jwkSource
));
...
...
@@ -194,13 +214,13 @@ public class AuthorizationServerConfig {
@Bean
public
OAuth2TokenCustomizer
<
JwtEncodingContext
>
jwtCustomizer
()
{
return
context
->
{
if
(
OAuth2TokenType
.
ACCESS_TOKEN
.
equals
(
context
.
getTokenType
())
&&
context
.
getPrincipal
()
instanceof
UsernamePasswordAuthenticationToken
)
{
if
(
OAuth2TokenType
.
ACCESS_TOKEN
.
equals
(
context
.
getTokenType
())
&&
context
.
getPrincipal
()
instanceof
UsernamePasswordAuthenticationToken
)
{
// Customize headers/claims for access_token
Optional
.
ofNullable
(
context
.
getPrincipal
().
getPrincipal
()).
ifPresent
(
principal
->
{
JwtClaimsSet
.
Builder
claims
=
context
.
getClaims
();
if
(
principal
instanceof
SysUserDetails
userDetails
)
{
claims
.
claim
(
"user_id"
,
String
.
valueOf
(
userDetails
.
getUserId
()));
}
else
if
(
principal
instanceof
Member
User
Details
userDetails
)
{
}
else
if
(
principal
instanceof
MemberDetails
userDetails
)
{
claims
.
claim
(
"member_id"
,
String
.
valueOf
(
userDetails
.
getId
()));
}
});
...
...
@@ -211,9 +231,84 @@ public class AuthorizationServerConfig {
};
}
@Bean
public
AuthenticationManager
authenticationManager
(
AuthenticationConfiguration
authenticationConfiguration
)
throws
Exception
{
return
authenticationConfiguration
.
getAuthenticationManager
();
}
/**
* 初始化创建商城管理客户端
*
* @param registeredClientRepository
*/
private
void
initMallAdminClient
(
JdbcRegisteredClientRepository
registeredClientRepository
)
{
String
clientId
=
"mall-admin"
;
String
clientSecret
=
"123456"
;
String
clientName
=
"商城管理客户端"
;
// 如果使用明文,在客户端认证的时候会自动升级加密方式(修改密码), 直接使用 bcrypt 加密避免不必要的麻烦
// 不开玩笑,官方ISSUE: https://github.com/spring-projects/spring-authorization-server/issues/1099
String
encodeSecret
=
passwordEncoder
().
encode
(
clientSecret
);
RegisteredClient
registeredMallAdminClient
=
registeredClientRepository
.
findByClientId
(
clientId
);
String
id
=
registeredMallAdminClient
!=
null
?
registeredMallAdminClient
.
getId
()
:
UUID
.
randomUUID
().
toString
();
RegisteredClient
mallAppClient
=
RegisteredClient
.
withId
(
id
)
.
clientId
(
clientId
)
.
clientSecret
(
encodeSecret
)
.
clientName
(
clientName
)
.
clientAuthenticationMethod
(
ClientAuthenticationMethod
.
CLIENT_SECRET_BASIC
)
.
authorizationGrantType
(
AuthorizationGrantType
.
AUTHORIZATION_CODE
)
.
authorizationGrantType
(
AuthorizationGrantType
.
REFRESH_TOKEN
)
.
authorizationGrantType
(
AuthorizationGrantType
.
CLIENT_CREDENTIALS
)
.
authorizationGrantType
(
AuthorizationGrantType
.
PASSWORD
)
// 密码模式
.
authorizationGrantType
(
CaptchaAuthenticationToken
.
CAPTCHA
)
// 验证码模式
.
redirectUri
(
"http://127.0.0.1:8080/authorized"
)
.
postLogoutRedirectUri
(
"http://127.0.0.1:8080/logged-out"
)
.
scope
(
OidcScopes
.
OPENID
)
.
scope
(
OidcScopes
.
PROFILE
)
.
clientSettings
(
ClientSettings
.
builder
().
requireAuthorizationConsent
(
true
).
build
())
.
build
();
registeredClientRepository
.
save
(
mallAppClient
);
}
/**
* 初始化创建商城APP客户端
*
* @param registeredClientRepository
*/
private
void
initMallAppClient
(
JdbcRegisteredClientRepository
registeredClientRepository
)
{
String
clientId
=
"mall-app"
;
String
clientSecret
=
"123456"
;
String
clientName
=
"商城APP客户端"
;
// 如果使用明文,在客户端认证的时候会自动升级加密方式,直接使用 bcrypt 加密避免不必要的麻烦
String
encodeSecret
=
passwordEncoder
().
encode
(
clientSecret
);
RegisteredClient
registeredMallAppClient
=
registeredClientRepository
.
findByClientId
(
clientId
);
String
id
=
registeredMallAppClient
!=
null
?
registeredMallAppClient
.
getId
()
:
UUID
.
randomUUID
().
toString
();
RegisteredClient
mallAppClient
=
RegisteredClient
.
withId
(
id
)
.
clientId
(
clientId
)
.
clientSecret
(
encodeSecret
)
.
clientName
(
clientName
)
.
clientAuthenticationMethod
(
ClientAuthenticationMethod
.
CLIENT_SECRET_BASIC
)
.
authorizationGrantType
(
AuthorizationGrantType
.
AUTHORIZATION_CODE
)
.
authorizationGrantType
(
AuthorizationGrantType
.
REFRESH_TOKEN
)
.
authorizationGrantType
(
AuthorizationGrantType
.
CLIENT_CREDENTIALS
)
.
authorizationGrantType
(
WxMiniAppAuthenticationToken
.
WECHAT_MINI_APP
)
// 微信小程序模式
.
authorizationGrantType
(
SmsCodeAuthenticationToken
.
SMS_CODE
)
// 短信验证码模式
.
redirectUri
(
"http://127.0.0.1:8080/authorized"
)
.
postLogoutRedirectUri
(
"http://127.0.0.1:8080/logged-out"
)
.
scope
(
OidcScopes
.
OPENID
)
.
scope
(
OidcScopes
.
PROFILE
)
.
clientSettings
(
ClientSettings
.
builder
().
requireAuthorizationConsent
(
true
).
build
())
.
build
();
registeredClientRepository
.
save
(
mallAppClient
);
}
}
youlai-auth/src/main/java/com/youlai/auth/config/SecurityConfig.java
浏览文件 @
ec404738
...
...
@@ -10,6 +10,8 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import
org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
;
import
org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer
;
import
org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer
;
import
org.springframework.security.crypto.factory.PasswordEncoderFactories
;
import
org.springframework.security.crypto.password.PasswordEncoder
;
import
org.springframework.security.web.SecurityFilterChain
;
import
java.util.List
;
...
...
youlai-auth/src/main/java/com/youlai/auth/userdetails/member/Member
User
Details.java
→
youlai-auth/src/main/java/com/youlai/auth/userdetails/member/MemberDetails.java
浏览文件 @
ec404738
package
com.youlai.auth.userdetails.member
;
import
cn.hutool.core.collection.CollectionUtil
;
import
com.youlai.common.constant.GlobalConstants
;
import
com.youlai.mall.ums.dto.MemberAuthDTO
;
import
lombok.Data
;
...
...
@@ -9,7 +8,6 @@ import org.springframework.security.core.userdetails.UserDetails;
import
java.util.Collection
;
import
java.util.Collections
;
import
java.util.HashSet
;
/**
...
...
@@ -19,7 +17,7 @@ import java.util.HashSet;
* @since 3.0.0
*/
@Data
public
class
Member
User
Details
implements
UserDetails
{
public
class
MemberDetails
implements
UserDetails
{
/**
* 会员ID
...
...
@@ -47,7 +45,7 @@ public class MemberUserDetails implements UserDetails {
*
* @param memAuthInfo 会员认证信息
*/
public
Member
User
Details
(
MemberAuthDTO
memAuthInfo
)
{
public
MemberDetails
(
MemberAuthDTO
memAuthInfo
)
{
this
.
setId
(
memAuthInfo
.
getId
());
this
.
setUsername
(
memAuthInfo
.
getUsername
());
this
.
setEnabled
(
GlobalConstants
.
STATUS_YES
.
equals
(
memAuthInfo
.
getStatus
()));
...
...
youlai-auth/src/main/java/com/youlai/auth/userdetails/member/
OpenidUs
erDetailsService.java
→
youlai-auth/src/main/java/com/youlai/auth/userdetails/member/
Memb
erDetailsService.java
浏览文件 @
ec404738
...
...
@@ -12,29 +12,53 @@ import org.springframework.security.authentication.AccountExpiredException;
import
org.springframework.security.authentication.DisabledException
;
import
org.springframework.security.authentication.LockedException
;
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
;
/**
*
会员信息(openid为主体)加载实现类
*
商城会员用户认证服务
*
* @author haoxr
* @since 3.0.0
*/
@Service
@RequiredArgsConstructor
public
class
OpenidUserDetailsService
implements
Us
erDetailsService
{
public
class
Memb
erDetailsService
{
private
final
MemberFeignClient
memberFeignClient
;
/**
* 手机号码认证方式
*
* @param mobile 手机号
* @return 用户信息
*/
public
UserDetails
loadUserByMobile
(
String
mobile
)
{
Result
<
MemberAuthDTO
>
result
=
memberFeignClient
.
loadUserByMobile
(
mobile
);
MemberAuthDTO
memberAuthInfo
;
if
(!(
Result
.
isSuccess
(
result
)
&&
(
memberAuthInfo
=
result
.
getData
())
!=
null
))
{
throw
new
UsernameNotFoundException
(
ResultCode
.
USER_NOT_EXIST
.
getMsg
());
}
MemberDetails
userDetails
=
new
MemberDetails
(
memberAuthInfo
);
if
(!
userDetails
.
isEnabled
())
{
throw
new
DisabledException
(
"该账户已被禁用!"
);
}
else
if
(!
userDetails
.
isAccountNonLocked
())
{
throw
new
LockedException
(
"该账号已被锁定!"
);
}
else
if
(!
userDetails
.
isAccountNonExpired
())
{
throw
new
AccountExpiredException
(
"该账号已过期!"
);
}
return
userDetails
;
}
/**
* 根据用户名获取用户信息
*
* @param openid 微信公众平台唯一身份标识
* @return {@link Member
User
Details}
* @return {@link MemberDetails}
*/
public
UserDetails
loadUserBy
Username
(
String
openid
)
{
public
UserDetails
loadUserBy
Openid
(
String
openid
)
{
// 根据 openid 获取微信用户认证信息
Result
<
MemberAuthDTO
>
getMemberAuthInfoResult
=
memberFeignClient
.
loadUserByOpenId
(
openid
);
...
...
@@ -61,7 +85,7 @@ public class OpenidUserDetailsService implements UserDetailsService {
throw
new
UsernameNotFoundException
(
ResultCode
.
USER_NOT_EXIST
.
getMsg
());
}
UserDetails
userDetails
=
new
Member
User
Details
(
memberAuthInfo
);
UserDetails
userDetails
=
new
MemberDetails
(
memberAuthInfo
);
if
(!
userDetails
.
isEnabled
())
{
throw
new
DisabledException
(
"该账户已被禁用!"
);
}
else
if
(!
userDetails
.
isAccountNonLocked
())
{
...
...
@@ -72,5 +96,4 @@ public class OpenidUserDetailsService implements UserDetailsService {
return
userDetails
;
}
}
youlai-auth/src/main/java/com/youlai/auth/userdetails/member/MobileUserDetailsService.java
已删除
100644 → 0
浏览文件 @
37a90229
package
com.youlai.auth.userdetails.member
;
import
cn.binarywang.wx.miniapp.api.WxMaService
;
import
cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult
;
import
cn.hutool.core.lang.Assert
;
import
com.youlai.common.enums.StatusEnum
;
import
com.youlai.common.result.Result
;
import
com.youlai.common.result.ResultCode
;
import
com.youlai.mall.ums.api.MemberFeignClient
;
import
com.youlai.mall.ums.dto.MemberAuthDTO
;
import
com.youlai.mall.ums.dto.MemberRegisterDto
;
import
lombok.RequiredArgsConstructor
;
import
lombok.SneakyThrows
;
import
org.springframework.security.authentication.AccountExpiredException
;
import
org.springframework.security.authentication.DisabledException
;
import
org.springframework.security.authentication.LockedException
;
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 haoxr
* @since 3.0.0
*/
@Service
@RequiredArgsConstructor
public
class
MobileUserDetailsService
implements
UserDetailsService
{
private
final
MemberFeignClient
memberFeignClient
;
/**
* 手机号码认证方式
*
* @param mobile 手机号
* @return 用户信息
*/
@Override
public
UserDetails
loadUserByUsername
(
String
mobile
)
{
Result
<
MemberAuthDTO
>
result
=
memberFeignClient
.
loadUserByMobile
(
mobile
);
MemberAuthDTO
memberAuthInfo
;
if
(!(
Result
.
isSuccess
(
result
)
&&
(
memberAuthInfo
=
result
.
getData
())
!=
null
))
{
throw
new
UsernameNotFoundException
(
ResultCode
.
USER_NOT_EXIST
.
getMsg
());
}
MemberUserDetails
userDetails
=
new
MemberUserDetails
(
memberAuthInfo
);
if
(!
userDetails
.
isEnabled
())
{
throw
new
DisabledException
(
"该账户已被禁用!"
);
}
else
if
(!
userDetails
.
isAccountNonLocked
())
{
throw
new
LockedException
(
"该账号已被锁定!"
);
}
else
if
(!
userDetails
.
isAccountNonExpired
())
{
throw
new
AccountExpiredException
(
"该账号已过期!"
);
}
return
userDetails
;
}
}
youlai-auth/src/main/java/com/youlai/auth/userdetails/user/SysUserDetails.java
浏览文件 @
ec404738
...
...
@@ -14,9 +14,7 @@ import java.util.stream.Collectors;
/**
* 系统用户信息
* <p>
* 包含用户名、密码和权限
* 系统用户信息(包含用户名、密码和权限)
* <p>
* 用户名和密码用于认证,认证成功之后授予权限
*
...
...
youlai-auth/src/main/java/com/youlai/auth/userdetails/user/SysUserDetailsService.java
浏览文件 @
ec404738
...
...
@@ -19,7 +19,6 @@ import org.springframework.stereotype.Service;
* @author haoxr
* @since 3.0.0
*/
@Primary
// UserDetailsService 默认的实现,其他需要显式声明
@Service
@RequiredArgsConstructor
public
class
SysUserDetailsService
implements
UserDetailsService
{
...
...
youlai-auth/src/main/resources/bootstrap-dev.yml
浏览文件 @
ec404738
...
...
@@ -2,6 +2,9 @@ server:
port
:
9000
spring
:
mvc
:
path-match
:
matching-strategy
:
ant_path_matcher
cloud
:
nacos
:
# 注册中心
...
...
@@ -17,5 +20,4 @@ spring:
data-id
:
youlai-common.yaml
refresh
:
true
username
:
nacos
password
:
nacos
password
:
nacos
\ No newline at end of file
youlai-auth/src/main/resources/bootstrap-prod.yml
浏览文件 @
ec404738
...
...
@@ -10,13 +10,12 @@ spring:
# 注册中心
discovery
:
server-addr
:
http://f.youlai.tech:8848
namespace
:
prod
-namespace-id
namespace
:
prod
# 配置中心
config
:
server-addr
:
${spring.cloud.nacos.discovery.server-addr}
file-extension
:
yaml
namespace
:
prod
-namespace-id
namespace
:
prod
shared-configs[0]
:
data-id
:
youlai-common.yaml
namespace
:
prod-namespace-id
refresh
:
true
\ No newline at end of file
youlai-auth/src/test/java/com/youlai/auth/authentication/CaptchaAuthenticationTests.java
0 → 100644
浏览文件 @
ec404738
package
com.youlai.auth.authentication
;
import
com.youlai.auth.authentication.captcha.CaptchaParameterNames
;
import
lombok.extern.slf4j.Slf4j
;
import
org.junit.jupiter.api.Test
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
;
import
org.springframework.boot.test.context.SpringBootTest
;
import
org.springframework.http.HttpHeaders
;
import
org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames
;
import
org.springframework.test.web.servlet.MockMvc
;
import
static
org
.
springframework
.
test
.
web
.
servlet
.
request
.
MockMvcRequestBuilders
.
post
;
import
static
org
.
springframework
.
test
.
web
.
servlet
.
result
.
MockMvcResultHandlers
.
print
;
import
static
org
.
springframework
.
test
.
web
.
servlet
.
result
.
MockMvcResultMatchers
.
jsonPath
;
import
static
org
.
springframework
.
test
.
web
.
servlet
.
result
.
MockMvcResultMatchers
.
status
;
@SpringBootTest
@AutoConfigureMockMvc
@Slf4j
public
class
CaptchaAuthenticationTests
{
@Autowired
private
MockMvc
mvc
;
@Test
void
testPasswordAuthentication
()
throws
Exception
{
HttpHeaders
headers
=
new
HttpHeaders
();
headers
.
setBasicAuth
(
"mall-admin"
,
"123456"
);
// @formatter:off
this
.
mvc
.
perform
(
post
(
"/oauth2/token"
)
.
param
(
OAuth2ParameterNames
.
GRANT_TYPE
,
"captcha"
)
.
param
(
OAuth2ParameterNames
.
USERNAME
,
"admin"
)
.
param
(
OAuth2ParameterNames
.
PASSWORD
,
"123456"
)
.
param
(
CaptchaParameterNames
.
VERIFY_CODE
,
"123456"
)
.
param
(
CaptchaParameterNames
.
VERIFY_CODE_KEY
,
"123456"
)
.
headers
(
headers
))
.
andDo
(
print
())
.
andExpect
(
status
().
isOk
())
.
andExpect
(
jsonPath
(
"$.access_token"
).
isNotEmpty
());
// @formatter:on
}
}
\ No newline at end of file
youlai-auth/src/test/java/com/youlai/auth/
security/authentication/password/ResourceOwner
PasswordAuthenticationTests.java
→
youlai-auth/src/test/java/com/youlai/auth/
authentication/
PasswordAuthenticationTests.java
浏览文件 @
ec404738
package
com.youlai.auth.
security.authentication.password
;
package
com.youlai.auth.
authentication
;
import
com.youlai.auth.authentication.wxminiapp.WxMiniAppAuthenticationToken
;
import
lombok.extern.slf4j.Slf4j
;
import
org.junit.jupiter.api.BeforeEach
;
import
org.junit.jupiter.api.Test
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
;
import
org.springframework.boot.test.context.SpringBootTest
;
import
org.springframework.http.HttpHeaders
;
import
org.springframework.security.crypto.password.PasswordEncoder
;
import
org.springframework.security.oauth2.core.AuthorizationGrantType
;
import
org.springframework.security.oauth2.core.ClientAuthenticationMethod
;
import
org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames
;
import
org.springframework.security.oauth2.core.oidc.OidcScopes
;
import
org.springframework.security.oauth2.server.authorization.client.RegisteredClient
;
import
org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository
;
import
org.springframework.security.oauth2.server.authorization.settings.ClientSettings
;
import
org.springframework.test.web.servlet.MockMvc
;
import
java.util.UUID
;
import
static
org
.
springframework
.
test
.
web
.
servlet
.
request
.
MockMvcRequestBuilders
.
post
;
import
static
org
.
springframework
.
test
.
web
.
servlet
.
result
.
MockMvcResultHandlers
.
print
;
import
static
org
.
springframework
.
test
.
web
.
servlet
.
result
.
MockMvcResultMatchers
.
jsonPath
;
...
...
@@ -29,59 +18,16 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
@SpringBootTest
@AutoConfigureMockMvc
@Slf4j
public
class
ResourceOwnerPasswordAuthenticationTests
{
private
final
String
clientId
=
"mall-app"
;
private
final
String
clientSecret
=
"secret"
;
@Autowired
private
RegisteredClientRepository
registeredClientRepository
;
public
class
PasswordAuthenticationTests
{
@Autowired
private
MockMvc
mvc
;
@Autowired
private
PasswordEncoder
passwordEncoder
;
@BeforeEach
public
void
setUp
()
{
// 注册 mall-app 客户端
//
String
encodeSecret
=
passwordEncoder
.
encode
(
clientSecret
);
RegisteredClient
messagingClient
=
RegisteredClient
.
withId
(
UUID
.
randomUUID
().
toString
())
.
clientId
(
clientId
)
.
clientSecret
(
encodeSecret
)
.
clientName
(
clientId
)
.
clientAuthenticationMethod
(
ClientAuthenticationMethod
.
CLIENT_SECRET_BASIC
)
.
authorizationGrantType
(
AuthorizationGrantType
.
AUTHORIZATION_CODE
)
.
authorizationGrantType
(
AuthorizationGrantType
.
REFRESH_TOKEN
)
.
authorizationGrantType
(
AuthorizationGrantType
.
CLIENT_CREDENTIALS
)
.
authorizationGrantType
(
AuthorizationGrantType
.
PASSWORD
)
.
authorizationGrantType
(
WxMiniAppAuthenticationToken
.
WECHAT_MINI_APP
)
.
redirectUri
(
"http://127.0.0.1:8080/login/oauth2/code/messaging-client-oidc"
)
.
redirectUri
(
"http://127.0.0.1:8080/authorized"
)
.
postLogoutRedirectUri
(
"http://127.0.0.1:8080/logged-out"
)
.
scope
(
OidcScopes
.
OPENID
)
.
scope
(
OidcScopes
.
PROFILE
)
.
scope
(
"message.read"
)
.
scope
(
"message.write"
)
.
clientSettings
(
ClientSettings
.
builder
().
requireAuthorizationConsent
(
true
).
build
())
.
build
();
RegisteredClient
registeredMessagingClient
=
registeredClientRepository
.
findByClientId
(
clientId
);
if
(
registeredMessagingClient
==
null
)
{
registeredClientRepository
.
save
(
messagingClient
);
}
}
@Test
void
test
LoginApiForOAuth2PasswordMode
()
throws
Exception
{
void
test
PasswordAuthentication
()
throws
Exception
{
HttpHeaders
headers
=
new
HttpHeaders
();
headers
.
setBasicAuth
(
"mall-a
pp"
,
"secret
"
);
headers
.
setBasicAuth
(
"mall-a
dmin"
,
"123456
"
);
// @formatter:off
this
.
mvc
.
perform
(
post
(
"/oauth2/token"
)
...
...
youlai-auth/src/test/java/com/youlai/auth/
security/authentication/password
/SmsCodeAuthenticationTests.java
→
youlai-auth/src/test/java/com/youlai/auth/
authentication
/SmsCodeAuthenticationTests.java
浏览文件 @
ec404738
package
com.youlai.auth.
security.authentication.password
;
package
com.youlai.auth.
authentication
;
import
com.youlai.auth.authentication.smscode.SmsCodeAuthenticationToken
;
import
com.youlai.auth.authentication.wxminiapp.WxMiniAppAuthenticationToken
;
import
lombok.extern.slf4j.Slf4j
;
import
org.junit.jupiter.api.BeforeEach
;
import
org.junit.jupiter.api.Test
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
;
import
org.springframework.boot.test.context.SpringBootTest
;
import
org.springframework.http.HttpHeaders
;
import
org.springframework.security.crypto.password.PasswordEncoder
;
import
org.springframework.security.oauth2.core.AuthorizationGrantType
;
import
org.springframework.security.oauth2.core.ClientAuthenticationMethod
;
import
org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames
;
import
org.springframework.security.oauth2.core.oidc.OidcScopes
;
import
org.springframework.security.oauth2.server.authorization.client.RegisteredClient
;
import
org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository
;
import
org.springframework.security.oauth2.server.authorization.settings.ClientSettings
;
import
org.springframework.test.web.servlet.MockMvc
;
import
java.util.UUID
;
import
static
org
.
springframework
.
test
.
web
.
servlet
.
request
.
MockMvcRequestBuilders
.
post
;
import
static
org
.
springframework
.
test
.
web
.
servlet
.
result
.
MockMvcResultHandlers
.
print
;
import
static
org
.
springframework
.
test
.
web
.
servlet
.
result
.
MockMvcResultMatchers
.
jsonPath
;
...
...
@@ -33,58 +21,14 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
public
class
SmsCodeAuthenticationTests
{
private
final
String
clientId
=
"mall-app"
;
private
final
String
clientSecret
=
"secret"
;
@Autowired
private
RegisteredClientRepository
registeredClientRepository
;
@Autowired
private
MockMvc
mvc
;
@Autowired
private
PasswordEncoder
passwordEncoder
;
@BeforeEach
public
void
setUp
()
{
// 注册 mall-app 客户端
String
encodeSecret
=
passwordEncoder
.
encode
(
clientSecret
);
RegisteredClient
messagingClient
=
RegisteredClient
.
withId
(
UUID
.
randomUUID
().
toString
())
.
clientId
(
clientId
)
.
clientSecret
(
encodeSecret
)
.
clientName
(
clientId
)
.
clientAuthenticationMethod
(
ClientAuthenticationMethod
.
CLIENT_SECRET_BASIC
)
.
authorizationGrantType
(
AuthorizationGrantType
.
AUTHORIZATION_CODE
)
.
authorizationGrantType
(
AuthorizationGrantType
.
REFRESH_TOKEN
)
.
authorizationGrantType
(
AuthorizationGrantType
.
CLIENT_CREDENTIALS
)
.
authorizationGrantType
(
AuthorizationGrantType
.
PASSWORD
)
.
authorizationGrantType
(
WxMiniAppAuthenticationToken
.
WECHAT_MINI_APP
)
.
authorizationGrantType
(
SmsCodeAuthenticationToken
.
SMS_CODE
)
.
redirectUri
(
"http://127.0.0.1:8080/login/oauth2/code/messaging-client-oidc"
)
.
redirectUri
(
"http://127.0.0.1:8080/authorized"
)
.
postLogoutRedirectUri
(
"http://127.0.0.1:8080/logged-out"
)
.
scope
(
OidcScopes
.
OPENID
)
.
scope
(
OidcScopes
.
PROFILE
)
.
scope
(
"message.read"
)
.
scope
(
"message.write"
)
.
clientSettings
(
ClientSettings
.
builder
().
requireAuthorizationConsent
(
true
).
build
())
.
build
();
RegisteredClient
registeredMessagingClient
=
registeredClientRepository
.
findByClientId
(
clientId
);
if
(
registeredMessagingClient
==
null
)
{
registeredClientRepository
.
save
(
messagingClient
);
}
}
@Test
void
testSmsCode
Mode
()
throws
Exception
{
void
testSmsCode
Authentication
()
throws
Exception
{
HttpHeaders
headers
=
new
HttpHeaders
();
headers
.
setBasicAuth
(
"mall-app"
,
"
secret
"
);
headers
.
setBasicAuth
(
"mall-app"
,
"
123456
"
);
// @formatter:off
this
.
mvc
.
perform
(
post
(
"/oauth2/token"
)
.
param
(
OAuth2ParameterNames
.
GRANT_TYPE
,
"sms_code"
)
.
param
(
"mobile"
,
"18866668888"
)
...
...
@@ -93,7 +37,6 @@ public class SmsCodeAuthenticationTests {
.
andDo
(
print
())
.
andExpect
(
status
().
isOk
())
.
andExpect
(
jsonPath
(
"$.access_token"
).
isNotEmpty
());
// @formatter:on
}
...
...
youlai-auth/src/test/java/com/youlai/auth/
security/authentication/password
/WechatMiniAppAuthenticationTests.java
→
youlai-auth/src/test/java/com/youlai/auth/
authentication
/WechatMiniAppAuthenticationTests.java
浏览文件 @
ec404738
package
com.youlai.auth.
security.authentication.password
;
package
com.youlai.auth.
authentication
;
import
com.youlai.auth.authentication.wxminiapp.WxMiniAppAuthenticationToken
;
import
lombok.extern.slf4j.Slf4j
;
import
org.junit.jupiter.api.BeforeEach
;
import
org.junit.jupiter.api.Test
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
;
import
org.springframework.boot.test.context.SpringBootTest
;
import
org.springframework.http.HttpHeaders
;
import
org.springframework.security.crypto.password.PasswordEncoder
;
import
org.springframework.security.oauth2.core.AuthorizationGrantType
;
import
org.springframework.security.oauth2.core.ClientAuthenticationMethod
;
import
org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames
;
import
org.springframework.security.oauth2.core.oidc.OidcScopes
;
import
org.springframework.security.oauth2.server.authorization.client.RegisteredClient
;
import
org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository
;
import
org.springframework.security.oauth2.server.authorization.settings.ClientSettings
;
import
org.springframework.test.web.servlet.MockMvc
;
import
java.util.UUID
;
import
static
org
.
springframework
.
test
.
web
.
servlet
.
request
.
MockMvcRequestBuilders
.
post
;
import
static
org
.
springframework
.
test
.
web
.
servlet
.
result
.
MockMvcResultHandlers
.
print
;
import
static
org
.
springframework
.
test
.
web
.
servlet
.
result
.
MockMvcResultMatchers
.
jsonPath
;
...
...
@@ -31,56 +20,13 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
@Slf4j
public
class
WechatMiniAppAuthenticationTests
{
private
final
String
clientId
=
"mall-app"
;
private
final
String
clientSecret
=
"secret"
;
@Autowired
private
RegisteredClientRepository
registeredClientRepository
;
@Autowired
private
MockMvc
mvc
;
@Autowired
private
PasswordEncoder
passwordEncoder
;
@BeforeEach
public
void
setUp
()
{
// 注册 mall-app 客户端
String
encodeSecret
=
passwordEncoder
.
encode
(
clientSecret
);
RegisteredClient
messagingClient
=
RegisteredClient
.
withId
(
UUID
.
randomUUID
().
toString
())
.
clientId
(
clientId
)
.
clientSecret
(
encodeSecret
)
.
clientName
(
clientId
)
.
clientAuthenticationMethod
(
ClientAuthenticationMethod
.
CLIENT_SECRET_BASIC
)
.
authorizationGrantType
(
AuthorizationGrantType
.
AUTHORIZATION_CODE
)
.
authorizationGrantType
(
AuthorizationGrantType
.
REFRESH_TOKEN
)
.
authorizationGrantType
(
AuthorizationGrantType
.
CLIENT_CREDENTIALS
)
.
authorizationGrantType
(
AuthorizationGrantType
.
PASSWORD
)
.
authorizationGrantType
(
WxMiniAppAuthenticationToken
.
WECHAT_MINI_APP
)
.
redirectUri
(
"http://127.0.0.1:8080/login/oauth2/code/messaging-client-oidc"
)
.
redirectUri
(
"http://127.0.0.1:8080/authorized"
)
.
postLogoutRedirectUri
(
"http://127.0.0.1:8080/logged-out"
)
.
scope
(
OidcScopes
.
OPENID
)
.
scope
(
OidcScopes
.
PROFILE
)
.
scope
(
"message.read"
)
.
scope
(
"message.write"
)
.
clientSettings
(
ClientSettings
.
builder
().
requireAuthorizationConsent
(
true
).
build
())
.
build
();
RegisteredClient
registeredMessagingClient
=
registeredClientRepository
.
findByClientId
(
clientId
);
if
(
registeredMessagingClient
==
null
)
{
registeredClientRepository
.
save
(
messagingClient
);
}
}
@Test
void
testWechatMiniAppPassword
Mode
()
throws
Exception
{
void
testWechatMiniAppPassword
Authentication
()
throws
Exception
{
HttpHeaders
headers
=
new
HttpHeaders
();
headers
.
setBasicAuth
(
"mall-app"
,
"
secret
"
);
headers
.
setBasicAuth
(
"mall-app"
,
"
123456
"
);
// @formatter:off
this
.
mvc
.
perform
(
post
(
"/oauth2/token"
)
...
...
youlai-gateway/src/main/java/com/youlai/gateway/captcha/handler/CaptchaHandler.java
浏览文件 @
ec404738
...
...
@@ -65,7 +65,7 @@ public class CaptchaHandler implements HandlerFunction<ServerResponse> {
String
captchaBase64
=
captcha
.
toBase64
();
Map
<
String
,
String
>
result
=
new
HashMap
<>(
2
);
result
.
put
(
"verifyCodeKey"
,
uuid
);
result
.
put
(
"verifyCode
Img
"
,
captchaBase64
);
result
.
put
(
"verifyCode
Base64
"
,
captchaBase64
);
return
ServerResponse
.
ok
().
body
(
BodyInserters
.
fromValue
(
Result
.
success
(
result
)));
}
...
...
youlai-gateway/src/main/resources/bootstrap-prod.yml
浏览文件 @
ec404738
...
...
@@ -10,12 +10,12 @@ spring:
nacos
:
discovery
:
server-addr
:
http://f.youlai.tech:8848
namespace
:
prod
-namespace-id
namespace
:
prod
config
:
server-addr
:
${spring.cloud.nacos.discovery.server-addr}
file-extension
:
yaml
namespace
:
prod
-namespace-id
namespace
:
prod
shared-configs[0]
:
data-id
:
youlai-common.yaml
namespace
:
prod
-namespace-id
namespace
:
prod
refresh
:
true
youlai-system/system-boot/src/main/java/com/youlai/system/controller/SysUserController.java
浏览文件 @
ec404738
...
...
@@ -162,7 +162,8 @@ public class SysUserController {
@PostMapping
(
"/_import"
)
public
Result
importUsers
(
@Parameter
(
description
=
"部门ID"
)
Long
deptId
,
MultipartFile
file
)
throws
IOException
{
UserImportListener
listener
=
new
UserImportListener
(
deptId
);
String
msg
=
importExcel
(
file
.
getInputStream
(),
UserImportVO
.
class
,
listener
);
EasyExcel
.
read
(
file
.
getInputStream
(),
UserImportVO
.
class
,
listener
).
sheet
().
doRead
();
String
msg
=
listener
.
getMsg
();
return
Result
.
success
(
msg
);
}
...
...
@@ -177,10 +178,4 @@ public class SysUserController {
EasyExcel
.
write
(
response
.
getOutputStream
(),
UserExportVO
.
class
).
sheet
(
"用户列表"
)
.
doWrite
(
exportUserList
);
}
public
static
<
T
>
String
importExcel
(
InputStream
is
,
Class
clazz
,
MyAnalysisEventListener
<
T
>
listener
)
{
EasyExcel
.
read
(
is
,
clazz
,
listener
).
sheet
().
doRead
();
return
listener
.
getMsg
();
}
}
youlai-system/system-boot/src/main/java/com/youlai/system/service/impl/SysUserServiceImpl.java
浏览文件 @
ec404738
...
...
@@ -21,7 +21,6 @@ import com.youlai.system.model.query.UserPageQuery;
import
com.youlai.system.model.vo.UserExportVO
;
import
com.youlai.system.model.vo.UserInfoVO
;
import
com.youlai.system.model.vo.UserPageVO
;
import
com.youlai.system.service.SysMenuService
;
import
com.youlai.system.service.SysRoleService
;
import
com.youlai.system.service.SysUserRoleService
;
import
com.youlai.system.service.SysUserService
;
...
...
@@ -50,8 +49,6 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
private
final
SysUserRoleService
userRoleService
;
private
final
SysMenuService
menuService
;
private
final
SysRoleService
roleService
;
private
final
UserConverter
userConverter
;
...
...
youlai-system/system-boot/src/main/resources/bootstrap-prod.yml
浏览文件 @
ec404738
...
...
@@ -11,13 +11,13 @@ spring:
nacos
:
discovery
:
server-addr
:
http://f.youlai.tech:8848
namespace
:
prod
-namespace-id
namespace
:
prod
config
:
server-addr
:
${spring.cloud.nacos.discovery.server-addr}
file-extension
:
yaml
namespace
:
prod
-namespace-id
namespace
:
prod
shared-configs[0]
:
data-id
:
youlai-common.yaml
namespace
:
prod
-namespace-id
namespace
:
prod
refresh
:
true
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录