Skip to content

Commit 2f3082b

Browse files
committed
✨ Spring OAuth2
1 parent 0e6d097 commit 2f3082b

File tree

9 files changed

+88
-43
lines changed

9 files changed

+88
-43
lines changed

twelvet-auth/src/main/java/com/twelvet/auth/config/AuthorizationServerConfiguration.java

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,21 @@ public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity h
8888

8989
DefaultSecurityFilterChain securityFilterChain = http.authorizeHttpRequests(authorizeRequests -> {
9090
// 自定义接口、端点暴露
91-
authorizeRequests
92-
.requestMatchers("/api/token/*", "/token/**", "/actuator/**", "/assets/**", "/error", "/v3/api-docs",
93-
"/login/oauth2/**")
91+
authorizeRequests.requestMatchers(
92+
// Swagger
93+
"/v3/api-docs",
94+
// 监控
95+
"/actuator/**",
96+
// 资源
97+
"/assets/**",
98+
// 错误信息
99+
"/error",
100+
// OAuth2
101+
"/token/**",
102+
// 第三方授权OAuth2
103+
"/login/oauth2/**",
104+
// api相关,token管理
105+
"/api/token/*")
94106
.permitAll();
95107
authorizeRequests.anyRequest().authenticated();
96108
}).build();

twelvet-auth/src/main/java/com/twelvet/auth/controller/Oauth2AuthController.java

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,7 @@
1111
import io.swagger.v3.oas.annotations.tags.Tag;
1212
import me.zhyd.oauth.model.AuthCallback;
1313
import org.springframework.beans.factory.annotation.Autowired;
14-
import org.springframework.web.bind.annotation.GetMapping;
15-
import org.springframework.web.bind.annotation.PathVariable;
16-
import org.springframework.web.bind.annotation.RequestMapping;
17-
import org.springframework.web.bind.annotation.RestController;
14+
import org.springframework.web.bind.annotation.*;
1815

1916
/**
2017
* <p>
@@ -23,7 +20,6 @@
2320
*
2421
* @since 2025/1/16
2522
*/
26-
@AuthIgnore(value = false)
2723
@Tag(description = "Oauth2AuthController", name = "OAuth2登录优化管理")
2824
@RestController
2925
@RequestMapping("/login/oauth2")
@@ -34,18 +30,12 @@ public class Oauth2AuthController extends TWTController {
3430

3531
/**
3632
* 获取登录地址
37-
* @return
33+
* @return String
3834
*/
3935
@Operation(summary = "获取登录地址")
4036
@GetMapping("/{oauthCode}")
4137
public JsonResult<String> getAuthorize(@PathVariable String oauthCode) {
4238
return JsonResult.success(oauthCode, oauth2AuthService.getAuthorize(oauthCode));
4339
}
4440

45-
@Operation(summary = "测试回调")
46-
@GetMapping("/code/{oauthCode}")
47-
public JsonResult<AuthCallback> login(@PathVariable String oauthCode, AuthCallback callback) {
48-
return JsonResult.success(callback);
49-
}
50-
5141
}

twelvet-auth/src/main/java/com/twelvet/auth/controller/TWTTokenEndpoint.java

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313
import io.swagger.v3.oas.annotations.Operation;
1414
import io.swagger.v3.oas.annotations.tags.Tag;
1515
import jakarta.servlet.http.HttpServletResponse;
16+
import org.checkerframework.checker.units.qual.A;
1617
import org.springframework.beans.factory.annotation.Autowired;
18+
import org.springframework.cache.Cache;
1719
import org.springframework.cache.CacheManager;
1820
import org.springframework.data.redis.core.RedisTemplate;
1921
import org.springframework.http.HttpHeaders;
@@ -39,10 +41,7 @@
3941
import org.springframework.web.servlet.ModelAndView;
4042

4143
import java.security.Principal;
42-
import java.util.ArrayList;
43-
import java.util.List;
44-
import java.util.Map;
45-
import java.util.Set;
44+
import java.util.*;
4645

4746
/**
4847
* @author twelvet
@@ -169,6 +168,9 @@ public void checkToken(String token, HttpServletResponse response) {
169168
@DeleteMapping("/{token}")
170169
public AjaxResult removeToken(@PathVariable("token") String token) {
171170
OAuth2Authorization authorization = authorizationService.findByToken(token, OAuth2TokenType.ACCESS_TOKEN);
171+
if (Objects.isNull(authorization)) {
172+
return AjaxResult.success();
173+
}
172174
OAuth2Authorization.Token<OAuth2AccessToken> accessToken = authorization.getAccessToken();
173175
if (accessToken == null || StrUtil.isBlank(accessToken.getToken().getTokenValue())) {
174176
return AjaxResult.success();
@@ -179,8 +181,12 @@ public AjaxResult removeToken(@PathVariable("token") String token) {
179181
* https://docs.spring.io/spring-framework/docs/6.1.x/javadoc-api/org/
180182
* springframework/cache/Cache.html
181183
*/
182-
cacheManager.getCache(CacheConstants.USER_DETAILS).evictIfPresent(authorization.getPrincipalName());
183-
// 清空access token
184+
Cache cache = cacheManager.getCache(CacheConstants.USER_DETAILS);
185+
if (Objects.isNull(cache)) {
186+
return AjaxResult.success();
187+
}
188+
cache.evictIfPresent(authorization.getPrincipalName());
189+
// 清空access token,会连带refresh token一起清空
184190
authorizationService.remove(authorization);
185191
// 处理自定义退出事件,保存相关日志
186192
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

twelvet-auth/src/main/java/com/twelvet/auth/controller/api/TokenEndpointApi.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import io.swagger.v3.oas.annotations.Operation;
1616
import io.swagger.v3.oas.annotations.tags.Tag;
1717
import org.springframework.beans.factory.annotation.Autowired;
18+
import org.springframework.cache.Cache;
1819
import org.springframework.cache.CacheManager;
1920
import org.springframework.data.redis.core.RedisTemplate;
2021
import org.springframework.security.authentication.event.LogoutSuccessEvent;
@@ -29,6 +30,7 @@
2930
import org.springframework.web.bind.annotation.*;
3031

3132
import java.util.List;
33+
import java.util.Objects;
3234
import java.util.Set;
3335
import java.util.stream.Collectors;
3436

@@ -58,10 +60,12 @@ public class TokenEndpointApi {
5860
* @return R<Void>
5961
*/
6062
@Operation(summary = "删除token")
61-
@AuthIgnore
6263
@DeleteMapping("/{token}")
6364
public R<Void> removeToken(@PathVariable("token") String token) {
6465
OAuth2Authorization authorization = authorizationService.findByToken(token, OAuth2TokenType.ACCESS_TOKEN);
66+
if (Objects.isNull(authorization)) {
67+
return R.ok();
68+
}
6569
OAuth2Authorization.Token<OAuth2AccessToken> accessToken = authorization.getAccessToken();
6670
if (accessToken == null || StrUtil.isBlank(accessToken.getToken().getTokenValue())) {
6771
return R.ok();
@@ -72,7 +76,11 @@ public R<Void> removeToken(@PathVariable("token") String token) {
7276
* https://docs.spring.io/spring-framework/docs/6.1.x/javadoc-api/org/
7377
* springframework/cache/Cache.html
7478
*/
75-
cacheManager.getCache(CacheConstants.USER_DETAILS).evictIfPresent(authorization.getPrincipalName());
79+
Cache cache = cacheManager.getCache(CacheConstants.USER_DETAILS);
80+
if (Objects.isNull(cache)) {
81+
return R.ok();
82+
}
83+
cache.evictIfPresent(authorization.getPrincipalName());
7684
// 清空access token
7785
authorizationService.remove(authorization);
7886
// 处理自定义退出事件,保存相关日志
@@ -88,7 +96,6 @@ public R<Void> removeToken(@PathVariable("token") String token) {
8896
* @return R<TableDataInfo>
8997
*/
9098
@Operation(summary = "分页token 信息")
91-
@AuthIgnore
9299
@GetMapping("/pageQuery")
93100
public R<TableDataInfo<TokenVo>> tokenList(TokenDTO tokenDTO) {
94101
String username = tokenDTO.getUsername();

twelvet/twelvet-framework/twelvet-framework-redis/src/main/java/com/twelvet/framework/redis/service/constants/CacheConstants.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,15 @@
77
*/
88
public interface CacheConstants {
99

10+
/**
11+
* 授权安全token前缀
12+
*/
13+
String AUTHORIZATION = "twelvet_token";
14+
1015
/**
1116
* oauth 缓存前缀
1217
*/
13-
String PROJECT_OAUTH_ACCESS = "token::access_token";
18+
String PROJECT_OAUTH_ACCESS = AUTHORIZATION + "::access_token";
1419

1520
/**
1621
* oauth 客户端信息

twelvet/twelvet-framework/twelvet-framework-security/src/main/java/com/twelvet/framework/security/constants/Oauth2ClientEnums.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.twelvet.framework.security.constants;
22

3+
import java.util.Arrays;
4+
35
/**
46
* <p>
57
* OAuth2客户端
@@ -36,4 +38,16 @@ public String getDescription() {
3638
return description;
3739
}
3840

41+
/**
42+
* 通过clientId获取枚举信息
43+
* @param clientId clientId
44+
* @return Oauth2ClientEnums
45+
*/
46+
public static Oauth2ClientEnums getByClientId(String clientId) {
47+
return Arrays.stream(Oauth2ClientEnums.values())
48+
.filter(oauth2ClientEnums -> oauth2ClientEnums.getClientId().equals(clientId))
49+
.findFirst()
50+
.orElse(null);
51+
}
52+
3953
}

twelvet/twelvet-framework/twelvet-framework-security/src/main/java/com/twelvet/framework/security/support/base/OAuth2ResourceOwnerBaseAuthenticationProvider.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,9 @@ public Authentication authenticate(Authentication authentication) throws Authent
124124
resouceOwnerBaseAuthenticationScopes);
125125

126126
RegisteredClient registeredClient = clientPrincipal.getRegisteredClient();
127+
if (Objects.isNull(registeredClient)) {
128+
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.UNAUTHORIZED_CLIENT);
129+
}
127130
checkClient(registeredClient);
128131

129132
Set<String> authorizedScopes;
@@ -171,23 +174,20 @@ public Authentication authenticate(Authentication authentication) throws Authent
171174
* .authenticate(authenticationToken);
172175
*/
173176

174-
AuthorizationGrantType authorizationGrantType = new AuthorizationGrantType(
175-
Oauth2GrantEnums.PASSWORD.getGrant());
176-
177177
// @formatter:off
178178
DefaultOAuth2TokenContext.Builder tokenContextBuilder = DefaultOAuth2TokenContext.builder()
179179
.registeredClient(registeredClient)
180180
.principal(authenticationToken)
181181
.authorizationServerContext(AuthorizationServerContextHolder.getContext())
182182
.authorizedScopes(authorizedScopes)
183-
.authorizationGrantType(authorizationGrantType)
183+
.authorizationGrantType(resouceOwnerBaseAuthenticationScopes.getAuthorizationGrantType())
184184
.authorizationGrant(resouceOwnerBaseAuthenticationScopes);
185185
// @formatter:on
186186

187187
OAuth2Authorization.Builder authorizationBuilder = OAuth2Authorization
188188
.withRegisteredClient(registeredClient)
189189
.principalName(authenticationToken.getName())
190-
.authorizationGrantType(authorizationGrantType)
190+
.authorizationGrantType(resouceOwnerBaseAuthenticationScopes.getAuthorizationGrantType())
191191
// 0.4.0 新增的方法
192192
.authorizedScopes(authorizedScopes);
193193

twelvet/twelvet-framework/twelvet-framework-security/src/main/java/com/twelvet/framework/security/support/grant/oauth2/github/OAuth2ResourceOwnerGiHubAuthenticationProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ public boolean supports(Class<?> authentication) {
124124
public void checkClient(RegisteredClient registeredClient) {
125125
assert registeredClient != null;
126126
if (!registeredClient.getAuthorizationGrantTypes()
127-
.contains(new AuthorizationGrantType(Oauth2GrantEnums.PASSWORD.getGrant()))) {
127+
.contains(new AuthorizationGrantType(Oauth2GrantEnums.GITHUB.getGrant()))) {
128128
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.UNAUTHORIZED_CLIENT);
129129
}
130130
}

twelvet/twelvet-framework/twelvet-framework-security/src/main/java/com/twelvet/framework/security/support/service/impl/TWTRedisOAuth2AuthorizationService.java

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package com.twelvet.framework.security.support.service.impl;
22

3+
import com.twelvet.framework.redis.service.constants.CacheConstants;
4+
import com.twelvet.framework.security.constants.Oauth2ClientEnums;
5+
import com.twelvet.framework.security.utils.SecurityUtils;
36
import org.springframework.beans.factory.annotation.Autowired;
47
import org.springframework.data.redis.core.RedisTemplate;
58
import org.springframework.data.redis.serializer.RedisSerializer;
@@ -16,6 +19,7 @@
1619
import java.time.temporal.ChronoUnit;
1720
import java.util.ArrayList;
1821
import java.util.List;
22+
import java.util.Map;
1923
import java.util.Objects;
2024
import java.util.concurrent.TimeUnit;
2125

@@ -28,8 +32,6 @@ public class TWTRedisOAuth2AuthorizationService implements OAuth2AuthorizationSe
2832

2933
private final static Long TIMEOUT = 10L;
3034

31-
private static final String AUTHORIZATION = "token";
32-
3335
@Autowired
3436
private RedisTemplate<String, Object> redisTemplate;
3537

@@ -47,8 +49,8 @@ public void save(OAuth2Authorization authorization) {
4749
if (isCode(authorization)) {
4850
OAuth2Authorization.Token<OAuth2AuthorizationCode> authorizationCode = authorization
4951
.getToken(OAuth2AuthorizationCode.class);
50-
OAuth2AuthorizationCode authorizationCodeToken = authorizationCode.getToken();
51-
long between = ChronoUnit.MINUTES.between(authorizationCodeToken.getIssuedAt(),
52+
OAuth2AuthorizationCode authorizationCodeToken = Objects.requireNonNull(authorizationCode).getToken();
53+
long between = ChronoUnit.MINUTES.between(Objects.requireNonNull(authorizationCodeToken.getIssuedAt()),
5254
authorizationCodeToken.getExpiresAt());
5355
redisTemplate.setValueSerializer(RedisSerializer.java());
5456
redisTemplate.opsForValue()
@@ -57,18 +59,22 @@ public void save(OAuth2Authorization authorization) {
5759
}
5860

5961
if (isRefreshToken(authorization)) {
60-
OAuth2RefreshToken refreshToken = authorization.getRefreshToken().getToken();
61-
long between = ChronoUnit.SECONDS.between(refreshToken.getIssuedAt(), refreshToken.getExpiresAt());
62+
OAuth2RefreshToken refreshToken = Objects.requireNonNull(authorization.getRefreshToken()).getToken();
63+
long between = ChronoUnit.SECONDS.between(Objects.requireNonNull(refreshToken.getIssuedAt()),
64+
refreshToken.getExpiresAt());
6265
redisTemplate.setValueSerializer(RedisSerializer.java());
6366
redisTemplate.opsForValue()
6467
.set(buildKey(OAuth2ParameterNames.REFRESH_TOKEN, refreshToken.getTokenValue()), authorization, between,
6568
TimeUnit.SECONDS);
6669
}
6770

68-
if (isAccessToken(authorization)) {
71+
if (isAccessToken(authorization)) { // 只处理accessToken的id搜索能力
6972
OAuth2AccessToken accessToken = authorization.getAccessToken().getToken();
70-
long between = ChronoUnit.SECONDS.between(accessToken.getIssuedAt(), accessToken.getExpiresAt());
73+
long between = ChronoUnit.SECONDS.between(Objects.requireNonNull(accessToken.getIssuedAt()),
74+
accessToken.getExpiresAt());
7175
redisTemplate.setValueSerializer(RedisSerializer.java());
76+
77+
// 储存用户token
7278
redisTemplate.opsForValue()
7379
.set(buildKey(OAuth2ParameterNames.ACCESS_TOKEN, accessToken.getTokenValue()), authorization, between,
7480
TimeUnit.SECONDS);
@@ -88,22 +94,27 @@ public void remove(OAuth2Authorization authorization) {
8894
if (isCode(authorization)) {
8995
OAuth2Authorization.Token<OAuth2AuthorizationCode> authorizationCode = authorization
9096
.getToken(OAuth2AuthorizationCode.class);
91-
OAuth2AuthorizationCode authorizationCodeToken = authorizationCode.getToken();
97+
OAuth2AuthorizationCode authorizationCodeToken = Objects.requireNonNull(authorizationCode).getToken();
9298
keys.add(buildKey(OAuth2ParameterNames.CODE, authorizationCodeToken.getTokenValue()));
9399
}
94100

95101
if (isRefreshToken(authorization)) {
96-
OAuth2RefreshToken refreshToken = authorization.getRefreshToken().getToken();
102+
OAuth2RefreshToken refreshToken = Objects.requireNonNull(authorization.getRefreshToken()).getToken();
97103
keys.add(buildKey(OAuth2ParameterNames.REFRESH_TOKEN, refreshToken.getTokenValue()));
98104
}
99105

100-
if (isAccessToken(authorization)) {
106+
if (isAccessToken(authorization)) { // 只处理accessToken的id搜索能力
101107
OAuth2AccessToken accessToken = authorization.getAccessToken().getToken();
102108
keys.add(buildKey(OAuth2ParameterNames.ACCESS_TOKEN, accessToken.getTokenValue()));
103109
}
104110
redisTemplate.delete(keys);
105111
}
106112

113+
/**
114+
* 通过ID查询Token
115+
* @param id the authorization identifier
116+
* @return OAuth2Authorization
117+
*/
107118
@Override
108119
@Nullable
109120
public OAuth2Authorization findById(String id) {
@@ -120,7 +131,7 @@ public OAuth2Authorization findByToken(String token, @Nullable OAuth2TokenType t
120131
}
121132

122133
private String buildKey(String type, String id) {
123-
return String.format("%s::%s::%s", AUTHORIZATION, type, id);
134+
return String.format("%s::%s::%s", CacheConstants.AUTHORIZATION, type, id);
124135
}
125136

126137
private static boolean isState(OAuth2Authorization authorization) {

0 commit comments

Comments
 (0)