refactor: 优化oauth2授权扩展

This commit is contained in:
hxr 2024-03-23 16:21:23 +08:00
parent 09359627a0
commit a1c68b15dc
8 changed files with 63 additions and 70 deletions

View File

@ -14,14 +14,14 @@ import com.nimbusds.jose.proc.SecurityContext;
import com.youlai.auth.model.SysUserDetails; import com.youlai.auth.model.SysUserDetails;
import com.youlai.auth.oauth2.extension.captcha.CaptchaAuthenticationConverter; import com.youlai.auth.oauth2.extension.captcha.CaptchaAuthenticationConverter;
import com.youlai.auth.oauth2.extension.captcha.CaptchaAuthenticationProvider; import com.youlai.auth.oauth2.extension.captcha.CaptchaAuthenticationProvider;
import com.youlai.auth.oauth2.extension.miniapp.WxMiniAppAuthenticationConverter; import com.youlai.auth.oauth2.extension.wechat.WechatAuthenticationConverter;
import com.youlai.auth.oauth2.extension.miniapp.WxMiniAppAuthenticationProvider; import com.youlai.auth.oauth2.extension.wechat.WechatAuthenticationProvider;
import com.youlai.auth.oauth2.extension.miniapp.WxMiniAppAuthenticationToken; import com.youlai.auth.oauth2.extension.wechat.WechatAuthenticationToken;
import com.youlai.auth.oauth2.extension.password.PasswordAuthenticationConverter; import com.youlai.auth.oauth2.extension.password.PasswordAuthenticationConverter;
import com.youlai.auth.oauth2.extension.password.PasswordAuthenticationProvider; import com.youlai.auth.oauth2.extension.password.PasswordAuthenticationProvider;
import com.youlai.auth.oauth2.extension.sms.SmsAuthenticationConverter; import com.youlai.auth.oauth2.extension.smscode.SmsCodeAuthenticationConverter;
import com.youlai.auth.oauth2.extension.sms.SmsAuthenticationProvider; import com.youlai.auth.oauth2.extension.smscode.SmsCodeAuthenticationProvider;
import com.youlai.auth.oauth2.extension.sms.SmsAuthenticationToken; import com.youlai.auth.oauth2.extension.smscode.SmsCodeAuthenticationToken;
import com.youlai.auth.oauth2.handler.MyAuthenticationFailureHandler; import com.youlai.auth.oauth2.handler.MyAuthenticationFailureHandler;
import com.youlai.auth.oauth2.handler.MyAuthenticationSuccessHandler; import com.youlai.auth.oauth2.handler.MyAuthenticationSuccessHandler;
import com.youlai.auth.oauth2.jackson.SysUserMixin; import com.youlai.auth.oauth2.jackson.SysUserMixin;
@ -96,8 +96,6 @@ public class AuthorizationServerConfig {
private final CustomOidcUserInfoService customOidcUserInfoService; private final CustomOidcUserInfoService customOidcUserInfoService;
private final OAuth2TokenCustomizer<JwtEncodingContext> jwtCustomizer; private final OAuth2TokenCustomizer<JwtEncodingContext> jwtCustomizer;
private static final String CUSTOM_CONSENT_PAGE_URI = "/oauth2/consent"; // 自定义授权页
private static final String CUSTOM_LOGIN_PAGE_URI = "/sso-login"; // 自定义登录页
private final StringRedisTemplate redisTemplate; private final StringRedisTemplate redisTemplate;
@ -119,8 +117,6 @@ public class AuthorizationServerConfig {
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http); OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
http.getConfigurer(OAuth2AuthorizationServerConfigurer.class) http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
.authorizationEndpoint(authorizationEndpoint -> authorizationEndpoint.consentPage(CUSTOM_CONSENT_PAGE_URI)) // 自定义授权页
// 自定义授权模式转换器(Converter) // 自定义授权模式转换器(Converter)
.tokenEndpoint(tokenEndpoint -> tokenEndpoint .tokenEndpoint(tokenEndpoint -> tokenEndpoint
.accessTokenRequestConverters( .accessTokenRequestConverters(
@ -130,8 +126,8 @@ public class AuthorizationServerConfig {
List.of( List.of(
new PasswordAuthenticationConverter(), new PasswordAuthenticationConverter(),
new CaptchaAuthenticationConverter(), new CaptchaAuthenticationConverter(),
new WxMiniAppAuthenticationConverter(), new WechatAuthenticationConverter(),
new SmsAuthenticationConverter() new SmsCodeAuthenticationConverter()
) )
) )
) )
@ -142,8 +138,8 @@ public class AuthorizationServerConfig {
List.of( List.of(
new PasswordAuthenticationProvider(authenticationManager, authorizationService, tokenGenerator), new PasswordAuthenticationProvider(authenticationManager, authorizationService, tokenGenerator),
new CaptchaAuthenticationProvider(authenticationManager, authorizationService, tokenGenerator, redisTemplate, codeGenerator), new CaptchaAuthenticationProvider(authenticationManager, authorizationService, tokenGenerator, redisTemplate, codeGenerator),
new WxMiniAppAuthenticationProvider(authorizationService, tokenGenerator, memberDetailsService, wxMaService), new WechatAuthenticationProvider(authorizationService, tokenGenerator, memberDetailsService, wxMaService),
new SmsAuthenticationProvider(authorizationService, tokenGenerator, memberDetailsService, redisTemplate) new SmsCodeAuthenticationProvider(authorizationService, tokenGenerator, memberDetailsService, redisTemplate)
) )
) )
) )
@ -161,17 +157,14 @@ public class AuthorizationServerConfig {
); );
http http
// 当用户未登录且尝试访问需要认证的端点时重定向至登录页面
.exceptionHandling((exceptions) -> exceptions .exceptionHandling((exceptions) -> exceptions
.defaultAuthenticationEntryPointFor( .defaultAuthenticationEntryPointFor(
new LoginUrlAuthenticationEntryPoint(CUSTOM_LOGIN_PAGE_URI), new LoginUrlAuthenticationEntryPoint("/login"),
new MediaTypeRequestMatcher(MediaType.TEXT_HTML) new MediaTypeRequestMatcher(MediaType.TEXT_HTML)
) )
) )
// Accept access tokens for User Info and/or Client Registration
.oauth2ResourceServer(oauth2ResourceServer -> .oauth2ResourceServer(oauth2ResourceServer ->
oauth2ResourceServer.jwt(Customizer.withDefaults())); oauth2ResourceServer.jwt(Customizer.withDefaults()));
return http.build(); return http.build();
} }
@ -374,8 +367,8 @@ public class AuthorizationServerConfig {
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE) .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN) .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS) .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
.authorizationGrantType(WxMiniAppAuthenticationToken.WECHAT_MINI_APP) // 微信小程序模式 .authorizationGrantType(WechatAuthenticationToken.WECHAT_MINI_APP) // 微信小程序模式
.authorizationGrantType(SmsAuthenticationToken.SMS_CODE) // 短信验证码模式 .authorizationGrantType(SmsCodeAuthenticationToken.SMS_CODE) // 短信验证码模式
.redirectUri("http://127.0.0.1:8080/authorized") .redirectUri("http://127.0.0.1:8080/authorized")
.postLogoutRedirectUri("http://127.0.0.1:8080/logged-out") .postLogoutRedirectUri("http://127.0.0.1:8080/logged-out")
.scope(OidcScopes.OPENID) .scope(OidcScopes.OPENID)

View File

@ -1,4 +1,4 @@
package com.youlai.auth.oauth2.extension.sms; package com.youlai.auth.oauth2.extension.smscode;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.youlai.auth.util.OAuth2EndpointUtils; import com.youlai.auth.util.OAuth2EndpointUtils;
@ -26,13 +26,13 @@ import java.util.stream.Collectors;
* @see org.springframework.security.oauth2.server.authorization.web.authentication.OAuth2AuthorizationCodeAuthenticationConverter * @see org.springframework.security.oauth2.server.authorization.web.authentication.OAuth2AuthorizationCodeAuthenticationConverter
* @since 3.0.0 * @since 3.0.0
*/ */
public class SmsAuthenticationConverter implements AuthenticationConverter { public class SmsCodeAuthenticationConverter implements AuthenticationConverter {
@Override @Override
public Authentication convert(HttpServletRequest request) { public Authentication convert(HttpServletRequest request) {
// 授权类型 (必需) // 授权类型 (必需)
String grantType = request.getParameter(OAuth2ParameterNames.GRANT_TYPE); String grantType = request.getParameter(OAuth2ParameterNames.GRANT_TYPE);
if (!SmsAuthenticationToken.SMS_CODE.getValue().equals(grantType)) { if (!SmsCodeAuthenticationToken.SMS_CODE.getValue().equals(grantType)) {
return null; return null;
} }
@ -57,20 +57,20 @@ public class SmsAuthenticationConverter implements AuthenticationConverter {
} }
// 手机号(必需) // 手机号(必需)
String mobile = parameters.getFirst(SmsParameterNames.MOBILE); String mobile = parameters.getFirst(SmsCodeParameterNames.MOBILE);
if (StrUtil.isBlank(mobile)) { if (StrUtil.isBlank(mobile)) {
OAuth2EndpointUtils.throwError( OAuth2EndpointUtils.throwError(
OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ErrorCodes.INVALID_REQUEST,
SmsParameterNames.MOBILE, SmsCodeParameterNames.MOBILE,
OAuth2EndpointUtils.ACCESS_TOKEN_REQUEST_ERROR_URI); OAuth2EndpointUtils.ACCESS_TOKEN_REQUEST_ERROR_URI);
} }
// 验证码(必需) // 验证码(必需)
String code = parameters.getFirst(SmsParameterNames.CODE); String code = parameters.getFirst(SmsCodeParameterNames.CODE);
if (StrUtil.isBlank(code)) { if (StrUtil.isBlank(code)) {
OAuth2EndpointUtils.throwError( OAuth2EndpointUtils.throwError(
OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ErrorCodes.INVALID_REQUEST,
SmsParameterNames.CODE, SmsCodeParameterNames.CODE,
OAuth2EndpointUtils.ACCESS_TOKEN_REQUEST_ERROR_URI); OAuth2EndpointUtils.ACCESS_TOKEN_REQUEST_ERROR_URI);
} }
@ -85,7 +85,7 @@ public class SmsAuthenticationConverter implements AuthenticationConverter {
) )
.collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().get(0))); .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().get(0)));
return new SmsAuthenticationToken( return new SmsCodeAuthenticationToken(
clientPrincipal, clientPrincipal,
requestedScopes, requestedScopes,
additionalParameters additionalParameters

View File

@ -1,4 +1,4 @@
package com.youlai.auth.oauth2.extension.sms; package com.youlai.auth.oauth2.extension.smscode;
import cn.hutool.core.lang.Assert; import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
@ -34,7 +34,7 @@ import java.util.Map;
* @since 3.0.0 * @since 3.0.0
*/ */
@Slf4j @Slf4j
public class SmsAuthenticationProvider implements AuthenticationProvider { public class SmsCodeAuthenticationProvider implements AuthenticationProvider {
private static final String ERROR_URI = "https://datatracker.ietf.org/doc/html/rfc6749#section-5.2"; private static final String ERROR_URI = "https://datatracker.ietf.org/doc/html/rfc6749#section-5.2";
@ -52,7 +52,7 @@ public class SmsAuthenticationProvider implements AuthenticationProvider {
* @param tokenGenerator the token generator * @param tokenGenerator the token generator
* @since 0.2.3 * @since 0.2.3
*/ */
public SmsAuthenticationProvider( public SmsCodeAuthenticationProvider(
OAuth2AuthorizationService authorizationService, OAuth2AuthorizationService authorizationService,
OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator, OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator,
MemberDetailsService memberDetailsService, MemberDetailsService memberDetailsService,
@ -72,21 +72,21 @@ public class SmsAuthenticationProvider implements AuthenticationProvider {
@Override @Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException { public Authentication authenticate(Authentication authentication) throws AuthenticationException {
SmsAuthenticationToken smsAuthenticationToken = (SmsAuthenticationToken) authentication; SmsCodeAuthenticationToken smsCodeAuthenticationToken = (SmsCodeAuthenticationToken) authentication;
OAuth2ClientAuthenticationToken clientPrincipal = OAuth2AuthenticationProviderUtils OAuth2ClientAuthenticationToken clientPrincipal = OAuth2AuthenticationProviderUtils
.getAuthenticatedClientElseThrowInvalidClient(smsAuthenticationToken); .getAuthenticatedClientElseThrowInvalidClient(smsCodeAuthenticationToken);
RegisteredClient registeredClient = clientPrincipal.getRegisteredClient(); RegisteredClient registeredClient = clientPrincipal.getRegisteredClient();
// 验证客户端是否支持授权类型(grant_type=wechat_mini_app) // 验证客户端是否支持授权类型(grant_type=wechat_mini_app)
if (!registeredClient.getAuthorizationGrantTypes().contains(SmsAuthenticationToken.SMS_CODE)) { if (!registeredClient.getAuthorizationGrantTypes().contains(SmsCodeAuthenticationToken.SMS_CODE)) {
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.UNAUTHORIZED_CLIENT); throw new OAuth2AuthenticationException(OAuth2ErrorCodes.UNAUTHORIZED_CLIENT);
} }
// 短信验证码校验 // 短信验证码校验
Map<String, Object> additionalParameters = smsAuthenticationToken.getAdditionalParameters(); Map<String, Object> additionalParameters = smsCodeAuthenticationToken.getAdditionalParameters();
String mobile = (String) additionalParameters.get(SmsParameterNames.MOBILE); String mobile = (String) additionalParameters.get(SmsCodeParameterNames.MOBILE);
String code = (String) additionalParameters.get(SmsParameterNames.CODE); String code = (String) additionalParameters.get(SmsCodeParameterNames.CODE);
if (!code.equals("666666")) { // 666666 是后门因为短信收费正式环境删除这个if if (!code.equals("666666")) { // 666666 是后门因为短信收费正式环境删除这个if
String codeKey = RedisConstants.LOGIN_SMS_CODE_PREFIX + mobile; String codeKey = RedisConstants.LOGIN_SMS_CODE_PREFIX + mobile;
@ -107,8 +107,8 @@ public class SmsAuthenticationProvider implements AuthenticationProvider {
.registeredClient(registeredClient) .registeredClient(registeredClient)
.principal(usernamePasswordAuthentication) .principal(usernamePasswordAuthentication)
.authorizationServerContext(AuthorizationServerContextHolder.getContext()) .authorizationServerContext(AuthorizationServerContextHolder.getContext())
.authorizationGrantType(SmsAuthenticationToken.SMS_CODE) .authorizationGrantType(SmsCodeAuthenticationToken.SMS_CODE)
.authorizationGrant(smsAuthenticationToken); .authorizationGrant(smsCodeAuthenticationToken);
// 生成访问令牌(Access Token) // 生成访问令牌(Access Token)
OAuth2TokenContext tokenContext = tokenContextBuilder.tokenType(OAuth2TokenType.ACCESS_TOKEN).build(); OAuth2TokenContext tokenContext = tokenContextBuilder.tokenType(OAuth2TokenType.ACCESS_TOKEN).build();
@ -124,7 +124,7 @@ public class SmsAuthenticationProvider implements AuthenticationProvider {
generatedAccessToken.getExpiresAt(), tokenContext.getAuthorizedScopes()); generatedAccessToken.getExpiresAt(), tokenContext.getAuthorizedScopes());
OAuth2Authorization.Builder authorizationBuilder = OAuth2Authorization.withRegisteredClient(registeredClient) OAuth2Authorization.Builder authorizationBuilder = OAuth2Authorization.withRegisteredClient(registeredClient)
.principalName(userDetails.getUsername()) .principalName(userDetails.getUsername())
.authorizationGrantType(SmsAuthenticationToken.SMS_CODE) .authorizationGrantType(SmsCodeAuthenticationToken.SMS_CODE)
.attribute(Principal.class.getName(), usernamePasswordAuthentication); .attribute(Principal.class.getName(), usernamePasswordAuthentication);
if (generatedAccessToken instanceof ClaimAccessor) { if (generatedAccessToken instanceof ClaimAccessor) {
authorizationBuilder.token(accessToken, (metadata) -> authorizationBuilder.token(accessToken, (metadata) ->
@ -159,7 +159,7 @@ public class SmsAuthenticationProvider implements AuthenticationProvider {
@Override @Override
public boolean supports(Class<?> authentication) { public boolean supports(Class<?> authentication) {
return SmsAuthenticationToken.class.isAssignableFrom(authentication); return SmsCodeAuthenticationToken.class.isAssignableFrom(authentication);
} }
} }

View File

@ -1,4 +1,4 @@
package com.youlai.auth.oauth2.extension.sms; package com.youlai.auth.oauth2.extension.smscode;
import jakarta.annotation.Nullable; import jakarta.annotation.Nullable;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
@ -14,10 +14,10 @@ import java.util.Set;
/** /**
* 短信验证码身份验证令牌 * 短信验证码身份验证令牌
* *
* @author haoxr * @author Ray Hao
* @since 3.0.0 * @since 3.0.0
*/ */
public class SmsAuthenticationToken extends OAuth2AuthorizationGrantAuthenticationToken { public class SmsCodeAuthenticationToken extends OAuth2AuthorizationGrantAuthenticationToken {
/** /**
* 令牌申请访问范围 * 令牌申请访问范围
@ -27,15 +27,15 @@ public class SmsAuthenticationToken extends OAuth2AuthorizationGrantAuthenticati
/** /**
* 授权类型(短信验证码: sms_code) * 授权类型(短信验证码: sms_code)
*/ */
public static final AuthorizationGrantType SMS_CODE = new AuthorizationGrantType("sms"); public static final AuthorizationGrantType SMS_CODE = new AuthorizationGrantType("sms_code");
protected SmsAuthenticationToken( protected SmsCodeAuthenticationToken(
Authentication clientPrincipal, Authentication clientPrincipal,
Set<String> scopes, Set<String> scopes,
@Nullable Map<String, Object> additionalParameters @Nullable Map<String, Object> additionalParameters
) { ) {
super(SmsAuthenticationToken.SMS_CODE, clientPrincipal, additionalParameters); super(SmsCodeAuthenticationToken.SMS_CODE, clientPrincipal, additionalParameters);
this.scopes = Collections.unmodifiableSet(scopes != null ? new HashSet<>(scopes) : Collections.emptySet()); this.scopes = Collections.unmodifiableSet(scopes != null ? new HashSet<>(scopes) : Collections.emptySet());
} }

View File

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.youlai.auth.oauth2.extension.sms; package com.youlai.auth.oauth2.extension.smscode;
/** /**
* 短信验证码模式参数名称常量 * 短信验证码模式参数名称常量
@ -22,7 +22,7 @@ package com.youlai.auth.oauth2.extension.sms;
* @author haoxr * @author haoxr
* @since 3.0.0 * @since 3.0.0
*/ */
public final class SmsParameterNames { public final class SmsCodeParameterNames {
/** /**
* 手机号 * 手机号
@ -35,7 +35,7 @@ public final class SmsParameterNames {
public static final String CODE = "code"; public static final String CODE = "code";
private SmsParameterNames() { private SmsCodeParameterNames() {
} }
} }

View File

@ -1,4 +1,4 @@
package com.youlai.auth.oauth2.extension.miniapp; package com.youlai.auth.oauth2.extension.wechat;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.youlai.auth.util.OAuth2EndpointUtils; import com.youlai.auth.util.OAuth2EndpointUtils;
@ -26,7 +26,7 @@ import java.util.stream.Collectors;
* @see org.springframework.security.oauth2.server.authorization.web.authentication.OAuth2AuthorizationCodeAuthenticationConverter * @see org.springframework.security.oauth2.server.authorization.web.authentication.OAuth2AuthorizationCodeAuthenticationConverter
* @since 3.0.0 * @since 3.0.0
*/ */
public class WxMiniAppAuthenticationConverter implements AuthenticationConverter { public class WechatAuthenticationConverter implements AuthenticationConverter {
public static final String ACCESS_TOKEN_REQUEST_ERROR_URI = "https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html"; public static final String ACCESS_TOKEN_REQUEST_ERROR_URI = "https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html";
@ -34,7 +34,7 @@ public class WxMiniAppAuthenticationConverter implements AuthenticationConverter
public Authentication convert(HttpServletRequest request) { public Authentication convert(HttpServletRequest request) {
// 授权类型 (必需) // 授权类型 (必需)
String grantType = request.getParameter(OAuth2ParameterNames.GRANT_TYPE); String grantType = request.getParameter(OAuth2ParameterNames.GRANT_TYPE);
if (!WxMiniAppAuthenticationToken.WECHAT_MINI_APP.getValue().equals(grantType)) { if (!WechatAuthenticationToken.WECHAT_MINI_APP.getValue().equals(grantType)) {
return null; return null;
} }
@ -76,7 +76,7 @@ public class WxMiniAppAuthenticationConverter implements AuthenticationConverter
) )
.collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().get(0))); .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().get(0)));
return new WxMiniAppAuthenticationToken( return new WechatAuthenticationToken(
clientPrincipal, clientPrincipal,
requestedScopes, requestedScopes,
additionalParameters additionalParameters

View File

@ -1,4 +1,4 @@
package com.youlai.auth.oauth2.extension.miniapp; package com.youlai.auth.oauth2.extension.wechat;
import cn.binarywang.wx.miniapp.api.WxMaService; import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult; import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
@ -35,7 +35,7 @@ import java.util.Map;
* @since 3.0.0 * @since 3.0.0
*/ */
@Slf4j @Slf4j
public class WxMiniAppAuthenticationProvider implements AuthenticationProvider { public class WechatAuthenticationProvider implements AuthenticationProvider {
private static final String ERROR_URI = "https://datatracker.ietf.org/doc/html/rfc6749#section-5.2"; private static final String ERROR_URI = "https://datatracker.ietf.org/doc/html/rfc6749#section-5.2";
@ -54,7 +54,7 @@ public class WxMiniAppAuthenticationProvider implements AuthenticationProvider {
* @param tokenGenerator the token generator * @param tokenGenerator the token generator
* @since 0.2.3 * @since 0.2.3
*/ */
public WxMiniAppAuthenticationProvider( public WechatAuthenticationProvider(
OAuth2AuthorizationService authorizationService, OAuth2AuthorizationService authorizationService,
OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator, OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator,
MemberDetailsService memberDetailsService, MemberDetailsService memberDetailsService,
@ -74,19 +74,19 @@ public class WxMiniAppAuthenticationProvider implements AuthenticationProvider {
@Override @Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException { public Authentication authenticate(Authentication authentication) throws AuthenticationException {
WxMiniAppAuthenticationToken wxMiniAppAuthenticationToken = (WxMiniAppAuthenticationToken) authentication; WechatAuthenticationToken wechatAuthenticationToken = (WechatAuthenticationToken) authentication;
OAuth2ClientAuthenticationToken clientPrincipal = OAuth2AuthenticationProviderUtils OAuth2ClientAuthenticationToken clientPrincipal = OAuth2AuthenticationProviderUtils
.getAuthenticatedClientElseThrowInvalidClient(wxMiniAppAuthenticationToken); .getAuthenticatedClientElseThrowInvalidClient(wechatAuthenticationToken);
RegisteredClient registeredClient = clientPrincipal.getRegisteredClient(); RegisteredClient registeredClient = clientPrincipal.getRegisteredClient();
// 验证客户端是否支持授权类型(grant_type=wechat_mini_app) // 验证客户端是否支持授权类型(grant_type=wechat_mini_app)
if (!registeredClient.getAuthorizationGrantTypes().contains(WxMiniAppAuthenticationToken.WECHAT_MINI_APP)) { if (!registeredClient.getAuthorizationGrantTypes().contains(WechatAuthenticationToken.WECHAT_MINI_APP)) {
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.UNAUTHORIZED_CLIENT); throw new OAuth2AuthenticationException(OAuth2ErrorCodes.UNAUTHORIZED_CLIENT);
} }
// 微信 code 获取 openid // 微信 code 获取 openid
Map<String, Object> additionalParameters = wxMiniAppAuthenticationToken.getAdditionalParameters(); Map<String, Object> additionalParameters = wechatAuthenticationToken.getAdditionalParameters();
String code = (String) additionalParameters.get(OAuth2ParameterNames.CODE); String code = (String) additionalParameters.get(OAuth2ParameterNames.CODE);
WxMaJscode2SessionResult sessionInfo; WxMaJscode2SessionResult sessionInfo;
try { try {
@ -106,8 +106,8 @@ public class WxMiniAppAuthenticationProvider implements AuthenticationProvider {
.registeredClient(registeredClient) .registeredClient(registeredClient)
.principal(usernamePasswordAuthentication) .principal(usernamePasswordAuthentication)
.authorizationServerContext(AuthorizationServerContextHolder.getContext()) .authorizationServerContext(AuthorizationServerContextHolder.getContext())
.authorizationGrantType(WxMiniAppAuthenticationToken.WECHAT_MINI_APP) .authorizationGrantType(WechatAuthenticationToken.WECHAT_MINI_APP)
.authorizationGrant(wxMiniAppAuthenticationToken); .authorizationGrant(wechatAuthenticationToken);
// 生成访问令牌(Access Token) // 生成访问令牌(Access Token)
OAuth2TokenContext tokenContext = tokenContextBuilder.tokenType(OAuth2TokenType.ACCESS_TOKEN).build(); OAuth2TokenContext tokenContext = tokenContextBuilder.tokenType(OAuth2TokenType.ACCESS_TOKEN).build();
@ -123,7 +123,7 @@ public class WxMiniAppAuthenticationProvider implements AuthenticationProvider {
generatedAccessToken.getExpiresAt(), tokenContext.getAuthorizedScopes()); generatedAccessToken.getExpiresAt(), tokenContext.getAuthorizedScopes());
OAuth2Authorization.Builder authorizationBuilder = OAuth2Authorization.withRegisteredClient(registeredClient) OAuth2Authorization.Builder authorizationBuilder = OAuth2Authorization.withRegisteredClient(registeredClient)
.principalName(userDetails.getUsername()) .principalName(userDetails.getUsername())
.authorizationGrantType(WxMiniAppAuthenticationToken.WECHAT_MINI_APP) .authorizationGrantType(WechatAuthenticationToken.WECHAT_MINI_APP)
.attribute(Principal.class.getName(), usernamePasswordAuthentication); .attribute(Principal.class.getName(), usernamePasswordAuthentication);
if (generatedAccessToken instanceof ClaimAccessor) { if (generatedAccessToken instanceof ClaimAccessor) {
authorizationBuilder.token(accessToken, (metadata) -> authorizationBuilder.token(accessToken, (metadata) ->
@ -157,7 +157,7 @@ public class WxMiniAppAuthenticationProvider implements AuthenticationProvider {
@Override @Override
public boolean supports(Class<?> authentication) { public boolean supports(Class<?> authentication) {
return WxMiniAppAuthenticationToken.class.isAssignableFrom(authentication); return WechatAuthenticationToken.class.isAssignableFrom(authentication);
} }
} }

View File

@ -1,4 +1,4 @@
package com.youlai.auth.oauth2.extension.miniapp; package com.youlai.auth.oauth2.extension.wechat;
import jakarta.annotation.Nullable; import jakarta.annotation.Nullable;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
@ -18,7 +18,7 @@ import java.util.Set;
* @see OAuth2AuthorizationGrantAuthenticationToken * @see OAuth2AuthorizationGrantAuthenticationToken
* @since 3.0.0 * @since 3.0.0
*/ */
public class WxMiniAppAuthenticationToken extends OAuth2AuthorizationGrantAuthenticationToken { public class WechatAuthenticationToken extends OAuth2AuthorizationGrantAuthenticationToken {
/** /**
* 令牌申请访问范围 * 令牌申请访问范围
@ -28,15 +28,15 @@ public class WxMiniAppAuthenticationToken extends OAuth2AuthorizationGrantAuthen
/** /**
* 授权类型微信小程序 * 授权类型微信小程序
*/ */
public static final AuthorizationGrantType WECHAT_MINI_APP = new AuthorizationGrantType("wx_mini_app"); public static final AuthorizationGrantType WECHAT_MINI_APP = new AuthorizationGrantType("wechat");
protected WxMiniAppAuthenticationToken( protected WechatAuthenticationToken(
Authentication clientPrincipal, Authentication clientPrincipal,
Set<String> scopes, Set<String> scopes,
@Nullable Map<String, Object> additionalParameters @Nullable Map<String, Object> additionalParameters
) { ) {
super(WxMiniAppAuthenticationToken.WECHAT_MINI_APP, clientPrincipal, additionalParameters); super(WechatAuthenticationToken.WECHAT_MINI_APP, clientPrincipal, additionalParameters);
this.scopes = Collections.unmodifiableSet(scopes != null ? new HashSet<>(scopes) : Collections.emptySet()); this.scopes = Collections.unmodifiableSet(scopes != null ? new HashSet<>(scopes) : Collections.emptySet());
} }