Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
有来技术
youlai-mall
提交
aa031f46
Y
youlai-mall
项目概览
有来技术
/
youlai-mall
通知
1
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 搜索 >>
提交
aa031f46
编写于
10月 04, 2021
作者:
有
有来技术
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat:webflux集成kaptcha验证码
上级
d86a9d54
变更
33
隐藏空白更改
内联
并排
Showing
33 changed file
with
579 addition
and
263 deletion
+579
-263
mall-ums/ums-api/src/main/java/com/youlai/mall/ums/api/MemberFeignClient.java
.../main/java/com/youlai/mall/ums/api/MemberFeignClient.java
+24
-6
mall-ums/ums-api/src/main/java/com/youlai/mall/ums/pojo/dto/MemberAuthDTO.java
...main/java/com/youlai/mall/ums/pojo/dto/MemberAuthDTO.java
+1
-1
mall-ums/ums-boot/src/main/java/com/youlai/mall/ums/controller/app/MemberController.java
.../com/youlai/mall/ums/controller/app/MemberController.java
+32
-14
pom.xml
pom.xml
+7
-1
youlai-admin/admin-api/src/main/java/com/youlai/admin/pojo/dto/UserAuthDTO.java
.../src/main/java/com/youlai/admin/pojo/dto/UserAuthDTO.java
+2
-0
youlai-auth/pom.xml
youlai-auth/pom.xml
+1
-0
youlai-auth/src/main/java/com/youlai/auth/common/constant/AuthConstants.java
...n/java/com/youlai/auth/common/constant/AuthConstants.java
+5
-1
youlai-auth/src/main/java/com/youlai/auth/common/jwt/JwtGenerator.java
...rc/main/java/com/youlai/auth/common/jwt/JwtGenerator.java
+0
-44
youlai-auth/src/main/java/com/youlai/auth/common/jwt/JwtPayloadBuilder.java
...in/java/com/youlai/auth/common/jwt/JwtPayloadBuilder.java
+0
-80
youlai-auth/src/main/java/com/youlai/auth/controller/OAuthController.java
...main/java/com/youlai/auth/controller/OAuthController.java
+8
-8
youlai-auth/src/main/java/com/youlai/auth/security/config/AuthorizationServerConfig.java
...oulai/auth/security/config/AuthorizationServerConfig.java
+26
-11
youlai-auth/src/main/java/com/youlai/auth/security/config/WebSecurityConfig.java
...va/com/youlai/auth/security/config/WebSecurityConfig.java
+1
-3
youlai-auth/src/main/java/com/youlai/auth/security/core/userdetails/member/MemberUserDetails.java
...h/security/core/userdetails/member/MemberUserDetails.java
+8
-3
youlai-auth/src/main/java/com/youlai/auth/security/core/userdetails/member/MemberUserDetailsServiceImpl.java
...core/userdetails/member/MemberUserDetailsServiceImpl.java
+32
-5
youlai-auth/src/main/java/com/youlai/auth/security/core/userdetails/user/SysUserDetails.java
...i/auth/security/core/userdetails/user/SysUserDetails.java
+4
-5
youlai-auth/src/main/java/com/youlai/auth/security/core/userdetails/user/SysUserDetailsServiceImpl.java
...rity/core/userdetails/user/SysUserDetailsServiceImpl.java
+1
-1
youlai-auth/src/main/java/com/youlai/auth/security/extension/PreAuthenticatedUserDetailsService.java
...ecurity/extension/PreAuthenticatedUserDetailsService.java
+61
-0
youlai-auth/src/main/java/com/youlai/auth/security/extension/memeber/wechat/WechatAuthenticationProvider.java
...xtension/memeber/wechat/WechatAuthenticationProvider.java
+3
-6
youlai-auth/src/main/java/com/youlai/auth/security/extension/memeber/wechat/WechatAuthenticationToken.java
...y/extension/memeber/wechat/WechatAuthenticationToken.java
+1
-1
youlai-auth/src/main/java/com/youlai/auth/security/extension/memeber/wechat/WechatTokenGranter.java
...security/extension/memeber/wechat/WechatTokenGranter.java
+1
-1
youlai-auth/src/main/java/com/youlai/auth/security/extension/memeber/wechat/WechatUserInfo.java
...uth/security/extension/memeber/wechat/WechatUserInfo.java
+2
-5
youlai-common/common-core/src/main/java/com/youlai/common/constant/AuthConstants.java
...c/main/java/com/youlai/common/constant/AuthConstants.java
+5
-0
youlai-common/common-core/src/main/java/com/youlai/common/enums/AuthenticationMethodEnum.java
...ava/com/youlai/common/enums/AuthenticationMethodEnum.java
+39
-0
youlai-common/common-core/src/main/java/com/youlai/common/enums/BusinessTypeEnum.java
...c/main/java/com/youlai/common/enums/BusinessTypeEnum.java
+4
-2
youlai-common/common-web/pom.xml
youlai-common/common-web/pom.xml
+5
-0
youlai-common/common-web/src/main/java/com/youlai/common/web/util/JwtUtils.java
...eb/src/main/java/com/youlai/common/web/util/JwtUtils.java
+0
-29
youlai-common/common-web/src/main/java/com/youlai/common/web/util/RequestUtils.java
...rc/main/java/com/youlai/common/web/util/RequestUtils.java
+83
-0
youlai-gateway/pom.xml
youlai-gateway/pom.xml
+6
-34
youlai-gateway/src/main/java/com/youlai/gateway/kaptcha/config/CaptchaConfig.java
...java/com/youlai/gateway/kaptcha/config/CaptchaConfig.java
+57
-0
youlai-gateway/src/main/java/com/youlai/gateway/kaptcha/handler/CaptchaImageHandler.java
...m/youlai/gateway/kaptcha/handler/CaptchaImageHandler.java
+63
-0
youlai-gateway/src/main/java/com/youlai/gateway/kaptcha/handler/KaptchaTextCreator.java
...om/youlai/gateway/kaptcha/handler/KaptchaTextCreator.java
+68
-0
youlai-gateway/src/main/java/com/youlai/gateway/router/CaptchaImageRouter.java
...in/java/com/youlai/gateway/router/CaptchaImageRouter.java
+28
-0
youlai-gateway/src/main/java/com/youlai/gateway/security/SecurityGlobalFilter.java
...ava/com/youlai/gateway/security/SecurityGlobalFilter.java
+1
-2
未找到文件。
mall-ums/ums-api/src/main/java/com/youlai/mall/ums/api/MemberFeignClient.java
浏览文件 @
aa031f46
...
...
@@ -29,22 +29,40 @@ public interface MemberFeignClient {
@GetMapping
(
"/app-api/v1/members/detail/{id}"
)
Result
<
UmsMember
>
getUserEntityById
(
@PathVariable
Long
id
);
/**
* 获取认证会员信息
*/
@GetMapping
(
"/app-api/v1/members/openid/{openid}"
)
Result
<
MemberAuthDTO
>
loadUserByOpenId
(
@PathVariable
String
openid
);
/**
* 扣减会员余额
*/
@PutMapping
(
"/app-api/v1/members/current/balances/_deduct"
)
<
T
>
Result
<
T
>
deductBalance
(
@RequestParam
Long
balances
);
<
T
>
Result
<
T
>
deductBalance
(
@RequestParam
Long
balances
);
/**
* 添加浏览记录
*/
@PostMapping
(
"/app-api/v1/members/view/history"
)
<
T
>
Result
<
T
>
addProductViewHistory
(
@RequestBody
ProductHistoryVO
product
);
/**
* 根据openId获取会员认证信息
*
* @param openid
* @return
*/
@GetMapping
(
"/app-api/v1/members/openid/{openid}"
)
Result
<
MemberAuthDTO
>
loadUserByOpenId
(
@PathVariable
String
openid
);
/**
* 根据手机号获取会员认证信息
*
* @param mobile
* @return
*/
@GetMapping
(
"/app-api/v1/members/mobile/{mobile}"
)
Result
<
MemberAuthDTO
>
loadUserByMobile
(
String
mobile
);
}
mall-ums/ums-api/src/main/java/com/youlai/mall/ums/pojo/dto/MemberAuthDTO.java
浏览文件 @
aa031f46
...
...
@@ -8,6 +8,6 @@ import lombok.Data;
public
class
MemberAuthDTO
{
private
Long
userId
;
private
String
openId
;
private
String
username
;
private
Integer
status
;
}
mall-ums/ums-boot/src/main/java/com/youlai/mall/ums/controller/app/MemberController.java
浏览文件 @
aa031f46
...
...
@@ -61,20 +61,6 @@ public class MemberController {
return
Result
.
success
(
user
);
}
@ApiOperation
(
value
=
"根据openid获取会员认证信息"
)
@ApiImplicitParam
(
name
=
"openid"
,
value
=
"微信身份唯一标识"
,
required
=
true
,
paramType
=
"path"
,
dataType
=
"String"
)
@GetMapping
(
"/openid/{openid}"
)
public
Result
<
MemberAuthDTO
>
getByOpenid
(
@PathVariable
String
openid
)
{
UmsMember
member
=
iUmsMemberService
.
getOne
(
new
LambdaQueryWrapper
<
UmsMember
>().
eq
(
UmsMember:
:
getOpenid
,
openid
)
.
select
(
UmsMember:
:
getId
,
UmsMember:
:
getOpenid
,
UmsMember:
:
getStatus
)
);
if
(
member
==
null
)
{
return
Result
.
failed
(
ResultCode
.
USER_NOT_EXIST
);
}
// 会员认证信息
MemberAuthDTO
memberAuth
=
new
MemberAuthDTO
(
member
.
getId
(),
member
.
getOpenid
(),
member
.
getStatus
());
return
Result
.
success
(
memberAuth
);
}
@ApiOperation
(
value
=
"新增会员"
)
@ApiImplicitParam
(
name
=
"member"
,
value
=
"实体JSON对象"
,
required
=
true
,
paramType
=
"body"
,
dataType
=
"UmsMember"
)
...
...
@@ -153,4 +139,36 @@ public class MemberController {
return
Result
.
success
(
Collections
.
emptySet
());
}
}
@ApiOperation
(
value
=
"根据openid获取会员认证信息"
)
@ApiImplicitParam
(
name
=
"openid"
,
value
=
"微信身份唯一标识"
,
required
=
true
,
paramType
=
"path"
,
dataType
=
"String"
)
@GetMapping
(
"/openid/{openid}"
)
public
Result
<
MemberAuthDTO
>
getByOpenid
(
@PathVariable
String
openid
)
{
UmsMember
member
=
iUmsMemberService
.
getOne
(
new
LambdaQueryWrapper
<
UmsMember
>()
.
eq
(
UmsMember:
:
getOpenid
,
openid
)
.
select
(
UmsMember:
:
getId
,
UmsMember:
:
getOpenid
,
UmsMember:
:
getStatus
)
);
if
(
member
==
null
)
{
return
Result
.
failed
(
ResultCode
.
USER_NOT_EXIST
);
}
MemberAuthDTO
memberAuth
=
new
MemberAuthDTO
(
member
.
getId
(),
member
.
getOpenid
(),
member
.
getStatus
());
return
Result
.
success
(
memberAuth
);
}
@ApiOperation
(
value
=
"根据手机号获取会员认证信息"
)
@ApiImplicitParam
(
name
=
"mobile"
,
value
=
"会员手机号码"
,
required
=
true
,
paramType
=
"path"
,
dataType
=
"String"
)
@GetMapping
(
"/mobile/{mobile}"
)
public
Result
<
MemberAuthDTO
>
getByMobile
(
@PathVariable
String
mobile
)
{
UmsMember
member
=
iUmsMemberService
.
getOne
(
new
LambdaQueryWrapper
<
UmsMember
>()
.
eq
(
UmsMember:
:
getMobile
,
mobile
)
.
select
(
UmsMember:
:
getId
,
UmsMember:
:
getMobile
,
UmsMember:
:
getStatus
)
);
if
(
member
==
null
)
{
return
Result
.
failed
(
ResultCode
.
USER_NOT_EXIST
);
}
MemberAuthDTO
memberAuth
=
new
MemberAuthDTO
(
member
.
getId
(),
member
.
getMobile
(),
member
.
getStatus
());
return
Result
.
success
(
memberAuth
);
}
}
pom.xml
浏览文件 @
aa031f46
...
...
@@ -56,7 +56,7 @@
<swagger.version>
1.6.2
</swagger.version>
<docker.image.prefix>
youlai
</docker.image.prefix>
<
dockerfile-maven-plugin.version>
1.4.13
</dockerfile-maven-plugin
.version>
<
kaptcha.version>
2.3.2
</kaptcha
.version>
</properties>
<dependencies>
...
...
@@ -263,6 +263,12 @@
<artifactId>
common-log
</artifactId>
<version>
${youlai.version}
</version>
</dependency>
<dependency>
<groupId>
com.github.penggle
</groupId>
<artifactId>
kaptcha
</artifactId>
<version>
${kaptcha.version}
</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
youlai-admin/admin-api/src/main/java/com/youlai/admin/pojo/dto/UserAuthDTO.java
浏览文件 @
aa031f46
...
...
@@ -38,4 +38,6 @@ public class UserAuthDTO {
*/
private
List
<
String
>
roles
;
}
youlai-auth/pom.xml
浏览文件 @
aa031f46
...
...
@@ -102,6 +102,7 @@
<groupId>
com.github.xiaoymin
</groupId>
<artifactId>
knife4j-micro-spring-boot-starter
</artifactId>
</dependency>
</dependencies>
<build>
...
...
youlai-auth/src/main/java/com/youlai/auth/common/constant/
O
AuthConstants.java
→
youlai-auth/src/main/java/com/youlai/auth/common/constant/AuthConstants.java
浏览文件 @
aa031f46
...
...
@@ -4,8 +4,12 @@ package com.youlai.auth.common.constant;
* @author <a href="mailto:xianrui0365@163.com">xianrui</a>
* @date 2021/9/30
*/
public
interface
O
AuthConstants
{
public
interface
AuthConstants
{
String
TEST_CLIENT_ID
=
"test"
;
String
ADMIN_CLIENT_ID
=
"mall-admin"
;
String
APP_CLIENT_ID
=
"mall-app"
;
}
youlai-auth/src/main/java/com/youlai/auth/common/jwt/JwtGenerator.java
已删除
100644 → 0
浏览文件 @
d86a9d54
package
com.youlai.auth.common.jwt
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.security.jwt.JwtHelper
;
import
org.springframework.security.jwt.crypto.sign.RsaSigner
;
import
org.springframework.stereotype.Component
;
import
java.security.KeyPair
;
import
java.security.interfaces.RSAPrivateKey
;
import
java.util.Map
;
import
java.util.Set
;
/**
* 描述: [类型描述]
* 创建时间: 2021-06-08
*
* @author hxr
* @version 1.0.0
* @update [序号][日期YYYY-MM-DD] [更改人姓名][变更描述]
*/
@Component
public
class
JwtGenerator
{
@Autowired
private
KeyPair
keyPair
;
public
String
createAccessToken
(
Set
<
String
>
authorities
,
Map
<
String
,
String
>
additional
)
{
String
payload
=
new
JwtPayloadBuilder
()
.
exp
(
12
*
3600
)
// 默认12小时
.
authorities
(
authorities
)
.
additional
(
additional
)
.
builder
();
RSAPrivateKey
privateKey
=
(
RSAPrivateKey
)
keyPair
.
getPrivate
();
RsaSigner
signer
=
new
RsaSigner
(
privateKey
);
String
accessToken
=
JwtHelper
.
encode
(
payload
,
signer
).
getEncoded
();
return
accessToken
;
}
}
youlai-auth/src/main/java/com/youlai/auth/common/jwt/JwtPayloadBuilder.java
已删除
100644 → 0
浏览文件 @
d86a9d54
package
com.youlai.auth.common.jwt
;
import
cn.hutool.core.collection.CollectionUtil
;
import
cn.hutool.core.util.IdUtil
;
import
cn.hutool.json.JSONUtil
;
import
java.time.LocalDateTime
;
import
java.time.ZoneOffset
;
import
java.util.HashMap
;
import
java.util.HashSet
;
import
java.util.Map
;
import
java.util.Set
;
/**
* 描述: [类型描述]
* 创建时间: 2021/6/8
* @author hxr
* @version 1.0.0
* @update [序号][日期YYYY-MM-DD] [更改人姓名][变更描述]
*/
public
class
JwtPayloadBuilder
{
private
Map
<
String
,
Object
>
payload
=
new
HashMap
<>();
/**
* jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击
**/
private
String
jti
=
IdUtil
.
simpleUUID
();
/**
* jwt的签发时间
**/
private
LocalDateTime
iat
=
LocalDateTime
.
now
();
/**
* jwt的过期时间,这个过期时间必须要大于签发时间
**/
private
LocalDateTime
exp
;
/**
* 权限集
*/
private
Set
<
String
>
authorities
=
new
HashSet
<>();
/**
* 附加的属性
*/
private
Map
<
String
,
String
>
additional
;
public
JwtPayloadBuilder
exp
(
int
seconds
)
{
this
.
exp
=
this
.
iat
.
plusSeconds
(
seconds
);
return
this
;
}
public
JwtPayloadBuilder
authorities
(
Set
<
String
>
authorities
)
{
this
.
authorities
=
authorities
;
return
this
;
}
public
JwtPayloadBuilder
additional
(
Map
<
String
,
String
>
additional
)
{
this
.
additional
=
additional
;
return
this
;
}
public
String
builder
()
{
payload
.
put
(
"jti"
,
jti
);
payload
.
put
(
"iat"
,
this
.
iat
.
toEpochSecond
(
ZoneOffset
.
of
(
"+8"
)));
payload
.
put
(
"exp"
,
this
.
exp
.
toEpochSecond
(
ZoneOffset
.
of
(
"+8"
)));
if
(
CollectionUtil
.
isNotEmpty
(
additional
))
{
payload
.
putAll
(
additional
);
}
payload
.
put
(
"authorities"
,
this
.
authorities
.
toArray
());
return
JSONUtil
.
toJsonStr
(
payload
);
}
}
youlai-auth/src/main/java/com/youlai/auth/controller/OAuthController.java
浏览文件 @
aa031f46
...
...
@@ -4,10 +4,10 @@ import cn.hutool.json.JSONObject;
import
cn.hutool.json.JSONUtil
;
import
com.nimbusds.jose.jwk.JWKSet
;
import
com.nimbusds.jose.jwk.RSAKey
;
import
com.youlai.auth.common.constant.OAuthConstants
;
import
com.youlai.common.constant.AuthConstants
;
import
com.youlai.auth.common.constant.AuthConstants
;
import
com.youlai.common.result.Result
;
import
com.youlai.common.web.util.JwtUtils
;
import
com.youlai.common.web.util.RequestUtils
;
import
io.swagger.annotations.Api
;
import
io.swagger.annotations.ApiImplicitParam
;
import
io.swagger.annotations.ApiImplicitParams
;
...
...
@@ -60,7 +60,7 @@ public class OAuthController {
* 方式一:client_id、client_secret放在请求路径中(注:当前版本已废弃)
* 方式二:放在请求头(Request Headers)中的Authorization字段,且经过加密,例如 Basic Y2xpZW50OnNlY3JldA== 明文等于 client:secret
*/
String
clientId
=
Jw
tUtils
.
getOAuth2ClientId
();
String
clientId
=
Reques
tUtils
.
getOAuth2ClientId
();
log
.
info
(
"OAuth认证授权 客户端ID:{},请求参数:{}"
,
clientId
,
JSONUtil
.
toJsonStr
(
parameters
));
/**
...
...
@@ -69,7 +69,7 @@ public class OAuthController {
* 请求头自动填充,token必须原生返回,否则显示 undefined undefined
* 账号/密码: client_id/client_secret : client/123456
*/
if
(
O
AuthConstants
.
TEST_CLIENT_ID
.
equals
(
clientId
))
{
if
(
AuthConstants
.
TEST_CLIENT_ID
.
equals
(
clientId
))
{
return
tokenEndpoint
.
postAccessToken
(
principal
,
parameters
).
getBody
();
}
...
...
@@ -81,15 +81,15 @@ public class OAuthController {
@DeleteMapping
(
"/logout"
)
public
Result
logout
()
{
JSONObject
payload
=
JwtUtils
.
getJwtPayload
();
String
jti
=
payload
.
getStr
(
AuthConstants
.
JWT_JTI
);
// JWT唯一标识
Long
expireTime
=
payload
.
getLong
(
AuthConstants
.
JWT_EXP
);
// JWT过期时间戳(单位:秒)
String
jti
=
payload
.
getStr
(
com
.
youlai
.
common
.
constant
.
AuthConstants
.
JWT_JTI
);
// JWT唯一标识
Long
expireTime
=
payload
.
getLong
(
com
.
youlai
.
common
.
constant
.
AuthConstants
.
JWT_EXP
);
// JWT过期时间戳(单位:秒)
if
(
expireTime
!=
null
)
{
long
currentTime
=
System
.
currentTimeMillis
()
/
1000
;
// 当前时间(单位:秒)
if
(
expireTime
>
currentTime
)
{
// token未过期,添加至缓存作为黑名单限制访问,缓存时间为token过期剩余时间
redisTemplate
.
opsForValue
().
set
(
AuthConstants
.
TOKEN_BLACKLIST_PREFIX
+
jti
,
null
,
(
expireTime
-
currentTime
),
TimeUnit
.
SECONDS
);
redisTemplate
.
opsForValue
().
set
(
com
.
youlai
.
common
.
constant
.
AuthConstants
.
TOKEN_BLACKLIST_PREFIX
+
jti
,
null
,
(
expireTime
-
currentTime
),
TimeUnit
.
SECONDS
);
}
}
else
{
// token 永不过期则永久加入黑名单
redisTemplate
.
opsForValue
().
set
(
AuthConstants
.
TOKEN_BLACKLIST_PREFIX
+
jti
,
null
);
redisTemplate
.
opsForValue
().
set
(
com
.
youlai
.
common
.
constant
.
AuthConstants
.
TOKEN_BLACKLIST_PREFIX
+
jti
,
null
);
}
return
Result
.
success
(
"注销成功"
);
}
...
...
youlai-auth/src/main/java/com/youlai/auth/security/config/AuthorizationServerConfig.java
浏览文件 @
aa031f46
package
com.youlai.auth.security.config
;
import
cn.hutool.core.collection.CollectionUtil
;
import
cn.hutool.core.util.StrUtil
;
import
cn.hutool.http.HttpStatus
;
import
cn.hutool.json.JSONUtil
;
import
com.youlai.auth.common.constant.AuthConstants
;
import
com.youlai.auth.security.core.clientdetails.ClientDetailsServiceImpl
;
import
com.youlai.auth.security.core.userdetails.member.MemberUserDetails
;
import
com.youlai.auth.security.core.userdetails.member.MemberUserDetailsServiceImpl
;
import
com.youlai.auth.security.core.userdetails.
system
.SysUserDetails
;
import
com.youlai.auth.security.core.userdetails.
system
.SysUserDetailsServiceImpl
;
import
com.youlai.auth.security.extension.wechat.WechatTokenGranter
;
import
com.youlai.auth.security.
core.CustomUserDetailsByNameServiceWrapper
;
import
com.youlai.auth.security.core.userdetails.
user
.SysUserDetails
;
import
com.youlai.auth.security.core.userdetails.
user
.SysUserDetailsServiceImpl
;
import
com.youlai.auth.security.extension.
memeber.
wechat.WechatTokenGranter
;
import
com.youlai.auth.security.
extension.PreAuthenticatedUserDetailsService
;
import
com.youlai.common.result.Result
;
import
com.youlai.common.result.ResultCode
;
import
lombok.RequiredArgsConstructor
;
...
...
@@ -53,8 +55,6 @@ public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdap
private
final
SysUserDetailsServiceImpl
sysUserDetailsService
;
private
final
MemberUserDetailsServiceImpl
memberUserDetailsService
;
private
final
List
<
UserDetailsService
>
userDetailsServices
;
/**
* OAuth2客户端
*/
...
...
@@ -87,10 +87,11 @@ public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdap
.
accessTokenConverter
(
jwtAccessTokenConverter
())
.
tokenEnhancer
(
tokenEnhancerChain
)
.
tokenGranter
(
compositeTokenGranter
)
// .userDetailsService(sysUserDetailsService)
// refresh token有两种使用方式:重复使用(true)、非重复使用(false),默认为true
// 1 重复使用:access token过期刷新时, refresh token过期时间未改变,仍以初次生成的时间为准
// 2 非重复使用:access token过期刷新时, refresh token过期时间延续,在refresh token有效期内刷新便永不失效达到无需再次登录的目的
//.userDetailsService(sysUserDetailsService)
/** refresh token有两种使用方式:重复使用(true)、非重复使用(false),默认为true
* 1 重复使用:access token过期刷新时, refresh token过期时间未改变,仍以初次生成的时间为准
* 2 非重复使用:access token过期刷新时, refresh token过期时间延续,在refresh token有效期内刷新便永不失效达到无需再次登录的目的
*/
.
reuseRefreshTokens
(
true
)
.
tokenServices
(
tokenServices
(
endpoints
));
// 自定义的TokenService
}
...
...
@@ -111,13 +112,21 @@ public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdap
tokenServices
.
setTokenEnhancer
(
tokenEnhancerChain
);
PreAuthenticatedAuthenticationProvider
provider
=
new
PreAuthenticatedAuthenticationProvider
();
provider
.
setPreAuthenticatedUserDetailsService
(
new
CustomUserDetailsByNameServiceWrapper
<>(
userDetailsServices
));
provider
.
setPreAuthenticatedUserDetailsService
(
new
PreAuthenticatedUserDetailsService
<>(
refreshTokenUserDetailsServiceMap
()
));
tokenServices
.
setAuthenticationManager
(
new
ProviderManager
(
Arrays
.
asList
(
provider
)));
return
tokenServices
;
}
public
Map
<
String
,
UserDetailsService
>
refreshTokenUserDetailsServiceMap
()
{
Map
<
String
,
UserDetailsService
>
clientUserDetailsServiceMap
=
new
HashMap
<>();
clientUserDetailsServiceMap
.
put
(
AuthConstants
.
ADMIN_CLIENT_ID
,
sysUserDetailsService
);
clientUserDetailsServiceMap
.
put
(
AuthConstants
.
APP_CLIENT_ID
,
memberUserDetailsService
);
return
clientUserDetailsServiceMap
;
}
/**
* 使用非对称加密算法对token签名
*/
...
...
@@ -150,10 +159,16 @@ public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdap
SysUserDetails
sysUserDetails
=
(
SysUserDetails
)
principal
;
additionalInfo
.
put
(
"userId"
,
sysUserDetails
.
getUserId
());
additionalInfo
.
put
(
"username"
,
sysUserDetails
.
getUsername
());
if
(
StrUtil
.
isNotBlank
(
sysUserDetails
.
getAuthenticationMethod
()))
{
additionalInfo
.
put
(
"authenticationMethod"
,
sysUserDetails
.
getAuthenticationMethod
());
}
}
else
if
(
principal
instanceof
MemberUserDetails
)
{
MemberUserDetails
memberUserDetails
=
(
MemberUserDetails
)
principal
;
additionalInfo
.
put
(
"userId"
,
memberUserDetails
.
getUserId
());
additionalInfo
.
put
(
"username"
,
memberUserDetails
.
getUsername
());
if
(
StrUtil
.
isNotBlank
(
memberUserDetails
.
getAuthenticationMethod
()))
{
additionalInfo
.
put
(
"authenticationMethod"
,
memberUserDetails
.
getAuthenticationMethod
());
}
}
((
DefaultOAuth2AccessToken
)
accessToken
).
setAdditionalInformation
(
additionalInfo
);
return
accessToken
;
...
...
youlai-auth/src/main/java/com/youlai/auth/security/config/WebSecurityConfig.java
浏览文件 @
aa031f46
package
com.youlai.auth.security.config
;
import
cn.binarywang.wx.miniapp.api.WxMaService
;
import
com.youlai.auth.security.core.userdetails.member.MemberUserDetailsServiceImpl
;
import
com.youlai.auth.security.core.userdetails.system.SysUserDetailsServiceImpl
;
import
com.youlai.auth.security.extension.wechat.WechatAuthenticationProvider
;
import
com.youlai.auth.security.extension.memeber.wechat.WechatAuthenticationProvider
;
import
com.youlai.mall.ums.api.MemberFeignClient
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
...
...
youlai-auth/src/main/java/com/youlai/auth/security/core/userdetails/member/MemberUserDetails.java
浏览文件 @
aa031f46
...
...
@@ -21,9 +21,14 @@ import java.util.HashSet;
public
class
MemberUserDetails
implements
UserDetails
{
private
Long
userId
;
private
String
openId
;
private
String
username
;
private
Boolean
enabled
;
/**
* 认证方式
*/
private
String
authenticationMethod
;
/**
* 小程序会员用户体系
...
...
@@ -32,7 +37,7 @@ public class MemberUserDetails implements UserDetails {
*/
public
MemberUserDetails
(
MemberAuthDTO
member
)
{
this
.
setUserId
(
member
.
getUserId
());
this
.
set
OpenId
(
member
.
getOpenId
());
this
.
set
Username
(
member
.
getUsername
());
this
.
setEnabled
(
GlobalConstants
.
STATUS_YES
.
equals
(
member
.
getStatus
()));
}
...
...
@@ -49,7 +54,7 @@ public class MemberUserDetails implements UserDetails {
@Override
public
String
getUsername
()
{
return
this
.
openId
;
return
this
.
username
;
}
@Override
...
...
youlai-auth/src/main/java/com/youlai/auth/security/core/userdetails/member/MemberUserDetailsServiceImpl.java
浏览文件 @
aa031f46
package
com.youlai.auth.security.core.userdetails.member
;
import
com.youlai.common.enums.AuthenticationMethodEnum
;
import
com.youlai.common.result.Result
;
import
com.youlai.common.result.ResultCode
;
import
com.youlai.mall.ums.api.MemberFeignClient
;
import
com.youlai.mall.ums.pojo.dto.MemberAuthDTO
;
import
lombok.RequiredArgsConstructor
;
import
lombok.SneakyThrows
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.security.authentication.AccountExpiredException
;
import
org.springframework.security.authentication.DisabledException
;
...
...
@@ -16,7 +16,7 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException;
import
org.springframework.stereotype.Service
;
/**
* 系统
用户体系业务类
* 系统
管理用户
*
* @author <a href="mailto:xianrui0365@163.com">xianrui</a>
*/
...
...
@@ -27,15 +27,20 @@ public class MemberUserDetailsServiceImpl implements UserDetailsService {
private
final
MemberFeignClient
memberFeignClient
;
@SneakyThrows
@Override
public
UserDetails
loadUserByUsername
(
String
openid
)
throws
UsernameNotFoundException
{
public
UserDetails
loadUserByUsername
(
String
username
)
{
return
null
;
}
public
UserDetails
loadUserByMobile
(
String
mobile
)
{
MemberUserDetails
userDetails
=
null
;
Result
<
MemberAuthDTO
>
result
=
memberFeignClient
.
loadUserBy
OpenId
(
openid
);
Result
<
MemberAuthDTO
>
result
=
memberFeignClient
.
loadUserBy
Mobile
(
mobile
);
if
(
Result
.
isSuccess
(
result
))
{
MemberAuthDTO
member
=
result
.
getData
();
if
(
null
!=
member
)
{
userDetails
=
new
MemberUserDetails
(
member
);
userDetails
.
setAuthenticationMethod
(
AuthenticationMethodEnum
.
MOBILE
.
getValue
());
// 认证方式:OpenId
}
}
if
(
userDetails
==
null
)
{
...
...
@@ -50,4 +55,26 @@ public class MemberUserDetailsServiceImpl implements UserDetailsService {
return
userDetails
;
}
public
UserDetails
loadUserByOpenId
(
String
openId
)
{
MemberUserDetails
userDetails
=
null
;
Result
<
MemberAuthDTO
>
result
=
memberFeignClient
.
loadUserByOpenId
(
openId
);
if
(
Result
.
isSuccess
(
result
))
{
MemberAuthDTO
member
=
result
.
getData
();
if
(
null
!=
member
)
{
userDetails
=
new
MemberUserDetails
(
member
);
userDetails
.
setAuthenticationMethod
(
AuthenticationMethodEnum
.
OPENID
.
getValue
());
// 认证方式:OpenId
}
}
if
(
userDetails
==
null
)
{
throw
new
UsernameNotFoundException
(
ResultCode
.
USER_NOT_EXIST
.
getMsg
());
}
else
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/security/core/userdetails/
system
/SysUserDetails.java
→
youlai-auth/src/main/java/com/youlai/auth/security/core/userdetails/
user
/SysUserDetails.java
浏览文件 @
aa031f46
package
com.youlai.auth.security.core.userdetails.
system
;
package
com.youlai.auth.security.core.userdetails.
user
;
import
cn.hutool.core.collection.CollectionUtil
;
import
com.youlai.admin.pojo.dto.UserAuthDTO
;
...
...
@@ -14,7 +14,7 @@ import java.util.Collection;
/**
* 用户认证信息
*
系统管理
用户认证信息
*
* @author <a href="mailto:xianrui0365@163.com">haoxianrui</a>
* @date 2021/9/27
...
...
@@ -26,6 +26,7 @@ public class SysUserDetails implements UserDetails {
* 扩展字段
*/
private
Long
userId
;
private
String
authenticationMethod
;
/**
* 默认字段
...
...
@@ -36,9 +37,7 @@ public class SysUserDetails implements UserDetails {
private
Collection
<
SimpleGrantedAuthority
>
authorities
;
/**
* 系统管理用户体系
*
* @param user 系统管理用户认证信息
* 系统管理用户
*/
public
SysUserDetails
(
UserAuthDTO
user
)
{
this
.
setUserId
(
user
.
getUserId
());
...
...
youlai-auth/src/main/java/com/youlai/auth/security/core/userdetails/
system
/SysUserDetailsServiceImpl.java
→
youlai-auth/src/main/java/com/youlai/auth/security/core/userdetails/
user
/SysUserDetailsServiceImpl.java
浏览文件 @
aa031f46
package
com.youlai.auth.security.core.userdetails.
system
;
package
com.youlai.auth.security.core.userdetails.
user
;
import
com.youlai.admin.api.UserFeignClient
;
import
com.youlai.admin.pojo.dto.UserAuthDTO
;
...
...
youlai-auth/src/main/java/com/youlai/auth/security/
core/CustomUserDetailsByNameServiceWrapper
.java
→
youlai-auth/src/main/java/com/youlai/auth/security/
extension/PreAuthenticatedUserDetailsService
.java
浏览文件 @
aa031f46
package
com.youlai.auth.security.
core
;
package
com.youlai.auth.security.
extension
;
import
com.youlai.auth.common.constant.AuthConstants
;
import
com.youlai.auth.security.core.userdetails.member.MemberUserDetailsServiceImpl
;
import
com.youlai.auth.security.core.userdetails.system.SysUserDetailsServiceImpl
;
import
com.youlai.auth.security.extension.wechat.WechatAuthenticationToken
;
import
com.youlai.common.web.util.JwtUtils
;
import
com.youlai.common.enums.AuthenticationMethodEnum
;
import
com.youlai.common.web.util.RequestUtils
;
import
lombok.NoArgsConstructor
;
import
org.springframework.beans.factory.InitializingBean
;
import
org.springframework.security.core.Authentication
;
...
...
@@ -11,51 +11,51 @@ import org.springframework.security.core.userdetails.AuthenticationUserDetailsSe
import
org.springframework.security.core.userdetails.UserDetails
;
import
org.springframework.security.core.userdetails.UserDetailsService
;
import
org.springframework.security.core.userdetails.UsernameNotFoundException
;
import
org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken
;
import
org.springframework.util.Assert
;
import
java.util.
List
;
import
java.util.
Map
;
/**
* UserDetailsService 工厂类
*
* @author <a href="mailto:xianrui0365@163.com">xianrui</a>
* @date 2021/10/2
*/
@NoArgsConstructor
public
class
CustomUserDetailsByNameServiceWrapper
<
T
extends
Authentication
>
implements
AuthenticationUserDetailsService
<
T
>,
InitializingBean
{
public
class
PreAuthenticatedUserDetailsService
<
T
extends
Authentication
>
implements
AuthenticationUserDetailsService
<
T
>,
InitializingBean
{
private
Map
<
String
,
UserDetailsService
>
userDetailsServiceMap
;
private
List
<
UserDetailsService
>
userDetailsServiceList
;
public
CustomUserDetailsByNameServiceWrapper
(
List
<
UserDetailsService
>
userDetailsServiceList
)
{
Assert
.
notNull
(
userDetailsServiceList
,
"userDetailsService cannot be null."
);
this
.
userDetailsServiceList
=
userDetailsServiceList
;
public
PreAuthenticatedUserDetailsService
(
Map
<
String
,
UserDetailsService
>
userDetailsServiceMap
)
{
Assert
.
notNull
(
userDetailsServiceMap
,
"userDetailsService cannot be null."
);
this
.
userDetailsServiceMap
=
userDetailsServiceMap
;
}
@Override
public
void
afterPropertiesSet
()
throws
Exception
{
Assert
.
notNull
(
this
.
userDetailsService
List
,
"UserDetailsService must be set"
);
Assert
.
notNull
(
this
.
userDetailsService
Map
,
"UserDetailsService must be set"
);
}
@Override
public
UserDetails
loadUserDetails
(
T
authentication
)
throws
UsernameNotFoundException
{
UserDetailsService
userDetailsService
=
null
;
String
clientId
=
JwtUtils
.
getOAuth2ClientId
();
for
(
UserDetailsService
detailsService
:
userDetailsServiceList
)
{
if
(
clientId
.
equals
(
"youlai-mall-weapp"
))
{
if
(
detailsService
instanceof
MemberUserDetailsServiceImpl
)
{
userDetailsService
=
detailsService
;
continue
;
}
}
else
{
if
(
detailsService
instanceof
SysUserDetailsServiceImpl
)
{
userDetailsService
=
detailsService
;
continue
;
}
String
clientId
=
RequestUtils
.
getOAuth2ClientId
();
AuthenticationMethodEnum
authenticationMethodEnum
=
AuthenticationMethodEnum
.
getByValue
(
RequestUtils
.
getAuthenticationMethod
());
UserDetailsService
userDetailsService
=
userDetailsServiceMap
.
get
(
clientId
);
if
(
clientId
.
equals
(
AuthConstants
.
APP_CLIENT_ID
))
{
MemberUserDetailsServiceImpl
memberUserDetailsService
=
(
MemberUserDetailsServiceImpl
)
userDetailsService
;
switch
(
authenticationMethodEnum
)
{
case
OPENID:
return
memberUserDetailsService
.
loadUserByOpenId
(
authentication
.
getName
());
default
:
return
memberUserDetailsService
.
loadUserByUsername
(
authentication
.
getName
());
}
}
else
if
(
clientId
.
equals
(
AuthConstants
.
ADMIN_CLIENT_ID
))
{
switch
(
authenticationMethodEnum
)
{
default
:
return
userDetailsService
.
loadUserByUsername
(
authentication
.
getName
());
}
}
else
{
return
userDetailsService
.
loadUserByUsername
(
authentication
.
getName
());
}
return
userDetailsService
.
loadUserByUsername
(
authentication
.
getName
());
}
}
youlai-auth/src/main/java/com/youlai/auth/security/extension/wechat/WechatAuthenticationProvider.java
→
youlai-auth/src/main/java/com/youlai/auth/security/extension/
memeber/
wechat/WechatAuthenticationProvider.java
浏览文件 @
aa031f46
package
com.youlai.auth.security.extension.wechat
;
package
com.youlai.auth.security.extension.
memeber.
wechat
;
import
cn.binarywang.wx.miniapp.api.WxMaService
;
import
cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult
;
import
cn.hutool.core.bean.BeanUtil
;
import
com.youlai.auth.security.core.userdetails.member.MemberUserDetailsServiceImpl
;
import
com.youlai.common.result.Result
;
import
com.youlai.common.result.ResultCode
;
import
com.youlai.mall.ums.api.MemberFeignClient
;
import
com.youlai.mall.ums.pojo.dto.MemberAuthDTO
;
import
com.youlai.mall.ums.pojo.entity.UmsMember
;
import
lombok.Data
;
import
lombok.SneakyThrows
;
import
me.chanjar.weixin.common.error.WxErrorException
;
import
org.springframework.security.authentication.AuthenticationProvider
;
import
org.springframework.security.core.Authentication
;
...
...
@@ -27,12 +27,9 @@ import java.util.HashSet;
public
class
WechatAuthenticationProvider
implements
AuthenticationProvider
{
private
UserDetailsService
userDetailsService
;
private
WxMaService
wxMaService
;
private
MemberFeignClient
memberFeignClient
;
/**
* 认证验证
*
...
...
@@ -62,7 +59,7 @@ public class WechatAuthenticationProvider implements AuthenticationProvider {
memberFeignClient
.
add
(
member
);
}
UserDetails
userDetails
=
userDetailsService
.
loadUserByUsername
(
openid
);
UserDetails
userDetails
=
((
MemberUserDetailsServiceImpl
)
userDetailsService
).
loadUserByOpenId
(
openid
);
WechatAuthenticationToken
result
=
new
WechatAuthenticationToken
(
userDetails
,
new
HashSet
<>());
result
.
setDetails
(
authentication
.
getDetails
());
return
result
;
...
...
youlai-auth/src/main/java/com/youlai/auth/security/extension/wechat/WechatAuthenticationToken.java
→
youlai-auth/src/main/java/com/youlai/auth/security/extension/
memeber/
wechat/WechatAuthenticationToken.java
浏览文件 @
aa031f46
package
com.youlai.auth.security.extension.wechat
;
package
com.youlai.auth.security.extension.
memeber.
wechat
;
import
lombok.Getter
;
import
org.springframework.security.authentication.AbstractAuthenticationToken
;
...
...
youlai-auth/src/main/java/com/youlai/auth/security/extension/wechat/WechatTokenGranter.java
→
youlai-auth/src/main/java/com/youlai/auth/security/extension/
memeber/
wechat/WechatTokenGranter.java
浏览文件 @
aa031f46
package
com.youlai.auth.security.extension.wechat
;
package
com.youlai.auth.security.extension.
memeber.
wechat
;
import
cn.hutool.json.JSONUtil
;
import
org.springframework.security.authentication.*
;
...
...
youlai-auth/src/main/java/com/youlai/auth/security/extension/wechat/WechatUserInfo.java
→
youlai-auth/src/main/java/com/youlai/auth/security/extension/
memeber/
wechat/WechatUserInfo.java
浏览文件 @
aa031f46
package
com.youlai.auth.security.extension.wechat
;
package
com.youlai.auth.security.extension.
memeber.
wechat
;
import
lombok.Data
;
/**
* 微信用户信息
*
* @author <a href="mailto:xianrui0365@163.com">xianrui</a>
* @date 2021/
9/29
* @date 2021/
10/4
*/
@Data
public
class
WechatUserInfo
{
private
String
avatarUrl
;
private
String
city
;
...
...
youlai-common/common-core/src/main/java/com/youlai/common/constant/AuthConstants.java
浏览文件 @
aa031f46
...
...
@@ -67,5 +67,10 @@ public interface AuthConstants {
*/
String
SAVE_MENU_PATH
=
"/youlai-admin/api/v1/menus"
;
/**
* 认证方式
*/
String
AUTHENTICATION_METHOD
=
"authenticationMethod"
;
}
youlai-common/common-core/src/main/java/com/youlai/common/enums/AuthenticationMethodEnum.java
0 → 100644
浏览文件 @
aa031f46
package
com.youlai.common.enums
;
import
lombok.Getter
;
/**
* 认证方式枚举
*
* @author <a href="mailto:xianrui0365@163.com">xianrui</a>
* @date 2021/10/4
*/
public
enum
AuthenticationMethodEnum
{
USERNAME
(
"username"
,
"用户名"
),
MOBILE
(
"mobile"
,
"手机号"
),
OPENID
(
"openId"
,
"开放式认证系统唯一身份标识"
);
@Getter
private
String
value
;
@Getter
private
String
label
;
AuthenticationMethodEnum
(
String
value
,
String
label
)
{
this
.
value
=
value
;
this
.
label
=
label
;
}
public
static
AuthenticationMethodEnum
getByValue
(
String
value
)
{
AuthenticationMethodEnum
authenticationMethodEnum
=
null
;
for
(
AuthenticationMethodEnum
item
:
values
())
{
if
(
item
.
getValue
().
equals
(
value
))
{
authenticationMethodEnum
=
item
;
continue
;
}
}
return
authenticationMethodEnum
;
}
}
youlai-common/common-core/src/main/java/com/youlai/common/enums/BusinessTypeEnum.java
浏览文件 @
aa031f46
...
...
@@ -27,11 +27,13 @@ public enum BusinessTypeEnum {
}
public
static
BusinessTypeEnum
getValue
(
String
code
)
{
BusinessTypeEnum
businessTypeEnum
=
null
;
for
(
BusinessTypeEnum
value
:
values
())
{
if
(
value
.
getCode
().
equals
(
code
))
{
return
value
;
businessTypeEnum
=
value
;
continue
;
}
}
return
null
;
return
businessTypeEnum
;
}
}
youlai-common/common-web/pom.xml
浏览文件 @
aa031f46
...
...
@@ -58,6 +58,11 @@
<artifactId>
ip2region
</artifactId>
</dependency>
<dependency>
<groupId>
com.nimbusds
</groupId>
<artifactId>
nimbus-jose-jwt
</artifactId>
</dependency>
</dependencies>
</project>
youlai-common/common-web/src/main/java/com/youlai/common/web/util/JwtUtils.java
浏览文件 @
aa031f46
...
...
@@ -55,36 +55,7 @@ public class JwtUtils {
return
username
;
}
/**
* 获取登录认证的客户端ID
*
* 兼容两种方式获取OAuth2客户端信息(client_id、client_secret)
* 方式一:client_id、client_secret放在请求路径中
* 方式二:放在请求头(Request Headers)中的Authorization字段,且经过加密,例如 Basic Y2xpZW50OnNlY3JldA== 明文等于 client:secret
*
* @return
*/
@SneakyThrows
public
static
String
getOAuth2ClientId
()
{
String
clientId
;
HttpServletRequest
request
=
((
ServletRequestAttributes
)
RequestContextHolder
.
getRequestAttributes
()).
getRequest
();
// 从请求路径中获取
clientId
=
request
.
getParameter
(
AuthConstants
.
CLIENT_ID_KEY
);
if
(
StrUtil
.
isNotBlank
(
clientId
))
{
return
clientId
;
}
// 从请求头获取
String
basic
=
request
.
getHeader
(
AuthConstants
.
AUTHORIZATION_KEY
);
if
(
StrUtil
.
isNotBlank
(
basic
)
&&
basic
.
startsWith
(
AuthConstants
.
BASIC_PREFIX
))
{
basic
=
basic
.
replace
(
AuthConstants
.
BASIC_PREFIX
,
Strings
.
EMPTY
);
String
basicPlainText
=
new
String
(
Base64
.
getDecoder
().
decode
(
basic
.
getBytes
(
StandardCharsets
.
UTF_8
)),
StandardCharsets
.
UTF_8
);
clientId
=
basicPlainText
.
split
(
":"
)[
0
];
//client:secret
}
return
clientId
;
}
/**
* JWT获取用户角色列表
...
...
youlai-common/common-web/src/main/java/com/youlai/common/web/util/RequestUtils.java
0 → 100644
浏览文件 @
aa031f46
package
com.youlai.common.web.util
;
import
cn.hutool.core.util.StrUtil
;
import
cn.hutool.json.JSONObject
;
import
cn.hutool.json.JSONUtil
;
import
com.nimbusds.jose.JWSObject
;
import
com.youlai.common.constant.AuthConstants
;
import
com.youlai.common.enums.AuthenticationMethodEnum
;
import
lombok.SneakyThrows
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.logging.log4j.util.Strings
;
import
org.springframework.web.context.request.RequestContextHolder
;
import
org.springframework.web.context.request.ServletRequestAttributes
;
import
javax.servlet.http.HttpServletRequest
;
import
java.nio.charset.StandardCharsets
;
import
java.util.Base64
;
/**
* 请求工具类
*
* @author xianrui
*/
@Slf4j
public
class
RequestUtils
{
@SneakyThrows
public
static
String
getGrantType
()
{
HttpServletRequest
request
=
((
ServletRequestAttributes
)
RequestContextHolder
.
getRequestAttributes
()).
getRequest
();
String
grantType
=
request
.
getParameter
(
AuthConstants
.
GRANT_TYPE_KEY
);
return
grantType
;
}
/**
* 获取登录认证的客户端ID
* <p>
* 兼容两种方式获取OAuth2客户端信息(client_id、client_secret)
* 方式一:client_id、client_secret放在请求路径中
* 方式二:放在请求头(Request Headers)中的Authorization字段,且经过加密,例如 Basic Y2xpZW50OnNlY3JldA== 明文等于 client:secret
*
* @return
*/
@SneakyThrows
public
static
String
getOAuth2ClientId
()
{
HttpServletRequest
request
=
((
ServletRequestAttributes
)
RequestContextHolder
.
getRequestAttributes
()).
getRequest
();
// 从请求路径中获取
String
clientId
=
request
.
getParameter
(
AuthConstants
.
CLIENT_ID_KEY
);
if
(
StrUtil
.
isNotBlank
(
clientId
))
{
return
clientId
;
}
// 从请求头获取
String
basic
=
request
.
getHeader
(
AuthConstants
.
AUTHORIZATION_KEY
);
if
(
StrUtil
.
isNotBlank
(
basic
)
&&
basic
.
startsWith
(
AuthConstants
.
BASIC_PREFIX
))
{
basic
=
basic
.
replace
(
AuthConstants
.
BASIC_PREFIX
,
Strings
.
EMPTY
);
String
basicPlainText
=
new
String
(
Base64
.
getDecoder
().
decode
(
basic
.
getBytes
(
StandardCharsets
.
UTF_8
)),
StandardCharsets
.
UTF_8
);
clientId
=
basicPlainText
.
split
(
":"
)[
0
];
//client:secret
}
return
clientId
;
}
/**
* 解析JWT获取获取认证方式
*
* @return
*/
@SneakyThrows
public
static
String
getAuthenticationMethod
()
{
HttpServletRequest
request
=
((
ServletRequestAttributes
)
RequestContextHolder
.
getRequestAttributes
()).
getRequest
();
String
refreshToken
=
request
.
getParameter
(
AuthConstants
.
REFRESH_TOKEN
);
String
payload
=
StrUtil
.
toString
(
JWSObject
.
parse
(
refreshToken
).
getPayload
());
JSONObject
jsonObject
=
JSONUtil
.
parseObj
(
payload
);
String
authenticationMethod
=
jsonObject
.
getStr
(
AuthConstants
.
AUTHENTICATION_METHOD
);
if
(
StrUtil
.
isBlank
(
authenticationMethod
))
{
authenticationMethod
=
AuthenticationMethodEnum
.
USERNAME
.
getValue
();
}
return
authenticationMethod
;
}
}
youlai-gateway/pom.xml
浏览文件 @
aa031f46
...
...
@@ -102,49 +102,21 @@
<artifactId>
common-redis
</artifactId>
</dependency>
<dependency>
<groupId>
com.github.penggle
</groupId>
<artifactId>
kaptcha
</artifactId>
</dependency>
</dependencies>
<build>
<finalName>
${project.artifactId}
</finalName>
<plugins>
<plugin>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-maven-plugin
</artifactId>
</plugin>
<plugin>
<groupId>
com.spotify
</groupId>
<artifactId>
docker-maven-plugin
</artifactId>
<version>
1.2.2
</version>
<!--将插件绑定在某个阶段执行-->
<executions>
<execution>
<id>
build-image
</id>
<phase>
package
</phase>
<goals>
<goal>
build
</goal>
</goals>
</execution>
</executions>
<configuration>
<imageName>
${project.artifactId}
</imageName>
<!--指定标签-->
<imageTags>
<imageTag>
latest
</imageTag>
</imageTags>
<!-- 指定 Dockerfile 路径-->
<dockerDirectory>
${project.basedir}/src/main/docker
</dockerDirectory>
<forceTags>
true
</forceTags>
<resources>
<resource>
<targetPath>
/
</targetPath>
<directory>
${project.build.directory}
</directory>
<include>
${project.build.finalName}.jar
</include>
</resource>
</resources>
</configuration>
</plugin>
</plugins>
</build>
...
...
youlai-gateway/src/main/java/com/youlai/gateway/kaptcha/config/CaptchaConfig.java
0 → 100644
浏览文件 @
aa031f46
package
com.youlai.gateway.kaptcha.config
;
import
com.google.code.kaptcha.impl.DefaultKaptcha
;
import
com.google.code.kaptcha.util.Config
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
java.util.Properties
;
/**
* @author <a href="mailto:xianrui0365@163.com">xianrui</a>
* @date 2021/10/4
*/
@Configuration
public
class
CaptchaConfig
{
@Bean
(
name
=
"captchaProducerMath"
)
public
DefaultKaptcha
getKaptchaBeanMath
()
{
DefaultKaptcha
defaultKaptcha
=
new
DefaultKaptcha
();
Properties
properties
=
new
Properties
();
// 是否有边框 默认为true 我们可以自己设置yes,no
properties
.
setProperty
(
"kaptcha.border"
,
"yes"
);
// 边框颜色 默认为Color.BLACK
properties
.
setProperty
(
"kaptcha.border.color"
,
"105,179,90"
);
// 验证码文本字符颜色 默认为Color.BLACK
properties
.
setProperty
(
"kaptcha.textproducer.font.color"
,
"blue"
);
// 验证码图片宽度 默认为200
properties
.
setProperty
(
"kaptcha.image.width"
,
"160"
);
// 验证码图片高度 默认为50
properties
.
setProperty
(
"kaptcha.image.height"
,
"60"
);
// 验证码文本字符大小 默认为40
properties
.
setProperty
(
"kaptcha.textproducer.font.size"
,
"35"
);
// KAPTCHA_SESSION_KEY
properties
.
setProperty
(
"kaptcha.session.key"
,
"kaptchaCodeMath"
);
// 验证码文本生成器
properties
.
setProperty
(
"kaptcha.textproducer.impl"
,
"com.youlai.gateway.kaptcha.handler.KaptchaTextCreator"
);
// 验证码文本字符间距 默认为2
properties
.
setProperty
(
"kaptcha.textproducer.char.space"
,
"3"
);
// 验证码文本字符长度 默认为5
properties
.
setProperty
(
"kaptcha.textproducer.char.length"
,
"6"
);
// 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1,
// fontSize)
properties
.
setProperty
(
"kaptcha.textproducer.font.names"
,
"Arial,Courier"
);
// 验证码噪点颜色 默认为Color.BLACK
properties
.
setProperty
(
"kaptcha.noise.color"
,
"white"
);
// 干扰实现类
properties
.
setProperty
(
"kaptcha.noise.impl"
,
"com.google.code.kaptcha.impl.NoNoise"
);
// 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple
// 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy
// 阴影com.google.code.kaptcha.impl.ShadowGimpy
properties
.
setProperty
(
"kaptcha.obscurificator.impl"
,
"com.google.code.kaptcha.impl.ShadowGimpy"
);
Config
config
=
new
Config
(
properties
);
defaultKaptcha
.
setConfig
(
config
);
return
defaultKaptcha
;
}
}
youlai-gateway/src/main/java/com/youlai/gateway/kaptcha/handler/CaptchaImageHandler.java
0 → 100644
浏览文件 @
aa031f46
package
com.youlai.gateway.kaptcha.handler
;
import
cn.hutool.core.io.FastByteArrayOutputStream
;
import
cn.hutool.core.util.IdUtil
;
import
com.google.code.kaptcha.Producer
;
import
lombok.RequiredArgsConstructor
;
import
org.springframework.core.io.ByteArrayResource
;
import
org.springframework.data.redis.core.RedisTemplate
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.http.MediaType
;
import
org.springframework.stereotype.Component
;
import
org.springframework.web.reactive.function.BodyInserters
;
import
org.springframework.web.reactive.function.server.HandlerFunction
;
import
org.springframework.web.reactive.function.server.ServerRequest
;
import
org.springframework.web.reactive.function.server.ServerResponse
;
import
reactor.core.publisher.Mono
;
import
javax.imageio.ImageIO
;
import
java.awt.image.BufferedImage
;
import
java.io.IOException
;
import
java.util.concurrent.TimeUnit
;
/**
* @author <a href="mailto:xianrui0365@163.com">xianrui</a>
* @date 2021/10/4
*/
@Component
@RequiredArgsConstructor
public
class
CaptchaImageHandler
implements
HandlerFunction
<
ServerResponse
>
{
//随机数code_key
public
static
final
String
DEFAULT_CODE_KEY
=
"random_code_"
;
private
final
Producer
producer
;
private
final
RedisTemplate
redisTemplate
;
@Override
public
Mono
<
ServerResponse
>
handle
(
ServerRequest
serverRequest
)
{
// 生成验证码
String
capText
=
producer
.
createText
();
String
capStr
=
capText
.
substring
(
0
,
capText
.
lastIndexOf
(
"@"
));
String
code
=
capText
.
substring
(
capText
.
lastIndexOf
(
"@"
)
+
1
);
BufferedImage
image
=
producer
.
createImage
(
capStr
);
// 保存验证码信息
String
randomStr
=
IdUtil
.
simpleUUID
();
redisTemplate
.
opsForValue
().
set
(
DEFAULT_CODE_KEY
+
randomStr
,
code
,
60
,
TimeUnit
.
SECONDS
);
// 转换流信息写出
FastByteArrayOutputStream
os
=
new
FastByteArrayOutputStream
();
try
{
ImageIO
.
write
(
image
,
"jpg"
,
os
);
}
catch
(
IOException
e
)
{
return
Mono
.
error
(
e
);
}
return
ServerResponse
.
status
(
HttpStatus
.
OK
)
.
contentType
(
MediaType
.
IMAGE_JPEG
)
.
header
(
"randomstr"
,
randomStr
)
.
body
(
BodyInserters
.
fromResource
(
new
ByteArrayResource
(
os
.
toByteArray
())));
}
}
youlai-gateway/src/main/java/com/youlai/gateway/kaptcha/handler/KaptchaTextCreator.java
0 → 100644
浏览文件 @
aa031f46
package
com.youlai.gateway.kaptcha.handler
;
import
com.google.code.kaptcha.text.impl.DefaultTextCreator
;
import
java.security.NoSuchAlgorithmException
;
import
java.security.SecureRandom
;
/**
* 验证码文本生成器
*
* @author <a href="mailto:xianrui0365@163.com">xianrui</a>
* @date 2021/10/4
*/
public
class
KaptchaTextCreator
extends
DefaultTextCreator
{
private
static
final
String
[]
CNUMBERS
=
"0,1,2,3,4,5,6,7,8,9,10"
.
split
(
","
);
private
SecureRandom
rand
=
SecureRandom
.
getInstanceStrong
();
public
KaptchaTextCreator
()
throws
NoSuchAlgorithmException
{
}
@Override
public
String
getText
()
{
Integer
result
=
0
;
int
x
=
this
.
rand
.
nextInt
(
10
);
int
y
=
this
.
rand
.
nextInt
(
10
);
StringBuilder
suChinese
=
new
StringBuilder
();
int
randomoperands
=
(
int
)
Math
.
round
(
rand
.
nextDouble
()
*
2
);
if
(
randomoperands
==
0
)
{
result
=
x
*
y
;
suChinese
.
append
(
CNUMBERS
[
x
]);
suChinese
.
append
(
"*"
);
suChinese
.
append
(
CNUMBERS
[
y
]);
}
else
if
(
randomoperands
==
1
)
{
if
(!(
x
==
0
)
&&
y
%
x
==
0
)
{
result
=
y
/
x
;
suChinese
.
append
(
CNUMBERS
[
y
]);
suChinese
.
append
(
"/"
);
suChinese
.
append
(
CNUMBERS
[
x
]);
}
else
{
result
=
x
+
y
;
suChinese
.
append
(
CNUMBERS
[
x
]);
suChinese
.
append
(
"+"
);
suChinese
.
append
(
CNUMBERS
[
y
]);
}
}
else
if
(
randomoperands
==
2
)
{
if
(
x
>=
y
)
{
result
=
x
-
y
;
suChinese
.
append
(
CNUMBERS
[
x
]);
suChinese
.
append
(
"-"
);
suChinese
.
append
(
CNUMBERS
[
y
]);
}
else
{
result
=
y
-
x
;
suChinese
.
append
(
CNUMBERS
[
y
]);
suChinese
.
append
(
"-"
);
suChinese
.
append
(
CNUMBERS
[
x
]);
}
}
else
{
result
=
x
+
y
;
suChinese
.
append
(
CNUMBERS
[
x
]);
suChinese
.
append
(
"+"
);
suChinese
.
append
(
CNUMBERS
[
y
]);
}
suChinese
.
append
(
"=?@"
+
result
);
return
suChinese
.
toString
();
}
}
youlai-gateway/src/main/java/com/youlai/gateway/router/CaptchaImageRouter.java
0 → 100644
浏览文件 @
aa031f46
package
com.youlai.gateway.router
;
import
com.youlai.gateway.kaptcha.handler.CaptchaImageHandler
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.http.MediaType
;
import
org.springframework.web.reactive.function.server.RequestPredicates
;
import
org.springframework.web.reactive.function.server.RouterFunction
;
import
org.springframework.web.reactive.function.server.RouterFunctions
;
import
org.springframework.web.reactive.function.server.ServerResponse
;
/**
* 图片验证码路由
*
* @author <a href="mailto:xianrui0365@163.com">xianrui</a>
* @date 2021/10/4
*/
@Configuration
public
class
CaptchaImageRouter
{
@Bean
public
RouterFunction
<
ServerResponse
>
routeFunction
(
CaptchaImageHandler
captchaImageHandler
)
{
return
RouterFunctions
.
route
(
RequestPredicates
.
GET
(
"/code"
)
.
and
(
RequestPredicates
.
accept
(
MediaType
.
TEXT_PLAIN
)),
captchaImageHandler:
:
handle
);
}
}
youlai-gateway/src/main/java/com/youlai/gateway/security/SecurityGlobalFilter.java
浏览文件 @
aa031f46
...
...
@@ -68,8 +68,7 @@ public class SecurityGlobalFilter implements GlobalFilter, Ordered {
// 解析JWT获取jti,以jti为key判断redis的黑名单列表是否存在,存在则拦截访问
token
=
StrUtil
.
replaceIgnoreCase
(
token
,
AuthConstants
.
JWT_PREFIX
,
Strings
.
EMPTY
);
JWSObject
jwsObject
=
JWSObject
.
parse
(
token
);
String
payload
=
jwsObject
.
getPayload
().
toString
();
String
payload
=
StrUtil
.
toString
(
JWSObject
.
parse
(
token
).
getPayload
());
JSONObject
jsonObject
=
JSONUtil
.
parseObj
(
payload
);
String
jti
=
jsonObject
.
getStr
(
AuthConstants
.
JWT_JTI
);
Boolean
isBlack
=
redisTemplate
.
hasKey
(
AuthConstants
.
TOKEN_BLACKLIST_PREFIX
+
jti
);
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录