mirror of
https://gitee.com/youlaitech/youlai-mall.git
synced 2024-12-22 20:54:26 +08:00
refactor: 认证中心升级(临时提交勿clone)
This commit is contained in:
parent
b019e6dda6
commit
84aa6da775
@ -98,7 +98,7 @@ public class ResourceOwnerPasswordAuthenticationProvider implements Authenticati
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 生成 access_token
|
// 生成 access_token
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
DefaultOAuth2TokenContext.Builder tokenContextBuilder = DefaultOAuth2TokenContext.builder()
|
DefaultOAuth2TokenContext.Builder tokenContextBuilder = DefaultOAuth2TokenContext.builder()
|
||||||
.registeredClient(registeredClient)
|
.registeredClient(registeredClient)
|
||||||
.principal(usernamePasswordAuthentication)
|
.principal(usernamePasswordAuthentication)
|
||||||
|
@ -18,7 +18,7 @@ public class ResourceOwnerPasswordAuthenticationToken extends OAuth2Authorizatio
|
|||||||
* @param clientPrincipal
|
* @param clientPrincipal
|
||||||
* @param additionalParameters
|
* @param additionalParameters
|
||||||
*/
|
*/
|
||||||
protected ResourceOwnerPasswordAuthenticationToken(
|
public ResourceOwnerPasswordAuthenticationToken(
|
||||||
Authentication clientPrincipal,
|
Authentication clientPrincipal,
|
||||||
@Nullable Set<String> scopes,
|
@Nullable Set<String> scopes,
|
||||||
Map<String, Object> additionalParameters
|
Map<String, Object> additionalParameters
|
||||||
|
@ -0,0 +1,129 @@
|
|||||||
|
package com.youlai.auth.authentication.wechat;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.youlai.auth.authentication.password.ResourceOwnerPasswordAuthenticationToken;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||||
|
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||||
|
import org.springframework.security.oauth2.core.OAuth2Error;
|
||||||
|
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
||||||
|
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||||
|
import org.springframework.security.web.authentication.AuthenticationConverter;
|
||||||
|
import org.springframework.util.LinkedMultiValueMap;
|
||||||
|
import org.springframework.util.MultiValueMap;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 参数解析
|
||||||
|
*
|
||||||
|
* @see org.springframework.security.oauth2.server.authorization.web.authentication.OAuth2AuthorizationCodeAuthenticationConverter
|
||||||
|
*/
|
||||||
|
public class WechatAuthenticationConverter implements AuthenticationConverter {
|
||||||
|
|
||||||
|
public static final String ACCESS_TOKEN_REQUEST_ERROR_URI = "https://datatracker.ietf.org/doc/html/rfc6749#section-5.2";
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Authentication convert(HttpServletRequest request) {
|
||||||
|
// grant_type (REQUIRED)
|
||||||
|
String grantType = request.getParameter(OAuth2ParameterNames.GRANT_TYPE);
|
||||||
|
if (!"wechat".equals(grantType)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiValueMap<String, String> parameters = getParameters(request);
|
||||||
|
|
||||||
|
// scope (OPTIONAL)
|
||||||
|
String scope = parameters.getFirst(OAuth2ParameterNames.SCOPE);
|
||||||
|
if (StringUtils.hasText(scope) &&
|
||||||
|
parameters.get(OAuth2ParameterNames.SCOPE).size() != 1) {
|
||||||
|
throwError(
|
||||||
|
OAuth2ErrorCodes.INVALID_REQUEST,
|
||||||
|
OAuth2ParameterNames.SCOPE,
|
||||||
|
ACCESS_TOKEN_REQUEST_ERROR_URI);
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<String> requestedScopes = null;
|
||||||
|
if (StringUtils.hasText(scope)) {
|
||||||
|
requestedScopes = new HashSet<>(
|
||||||
|
Arrays.asList(StringUtils.delimitedListToStringArray(scope, " ")));
|
||||||
|
}
|
||||||
|
|
||||||
|
// code (REQUIRED)
|
||||||
|
String code = parameters.getFirst("code");
|
||||||
|
if (StrUtil.isBlank(code)) {
|
||||||
|
throwError(
|
||||||
|
OAuth2ErrorCodes.INVALID_REQUEST,
|
||||||
|
"code",
|
||||||
|
ACCESS_TOKEN_REQUEST_ERROR_URI);
|
||||||
|
}
|
||||||
|
|
||||||
|
// encryptedData (REQUIRED)
|
||||||
|
String encryptedData = parameters.getFirst("encryptedData");
|
||||||
|
if (StrUtil.isBlank(encryptedData)) {
|
||||||
|
throwError(
|
||||||
|
OAuth2ErrorCodes.INVALID_REQUEST,
|
||||||
|
"encryptedData",
|
||||||
|
ACCESS_TOKEN_REQUEST_ERROR_URI);
|
||||||
|
}
|
||||||
|
|
||||||
|
// iv (REQUIRED)
|
||||||
|
String iv = parameters.getFirst("iv");
|
||||||
|
if (StrUtil.isBlank(iv)) {
|
||||||
|
throwError(
|
||||||
|
OAuth2ErrorCodes.INVALID_REQUEST,
|
||||||
|
"iv",
|
||||||
|
ACCESS_TOKEN_REQUEST_ERROR_URI);
|
||||||
|
}
|
||||||
|
|
||||||
|
Authentication clientPrincipal = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
if (clientPrincipal == null) {
|
||||||
|
throwError(
|
||||||
|
OAuth2ErrorCodes.INVALID_REQUEST,
|
||||||
|
OAuth2ErrorCodes.INVALID_CLIENT,
|
||||||
|
ACCESS_TOKEN_REQUEST_ERROR_URI);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, Object> additionalParameters = parameters
|
||||||
|
.entrySet()
|
||||||
|
.stream()
|
||||||
|
.filter(e -> !e.getKey().equals(OAuth2ParameterNames.GRANT_TYPE) &&
|
||||||
|
!e.getKey().equals(OAuth2ParameterNames.SCOPE))
|
||||||
|
.collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().get(0)));
|
||||||
|
|
||||||
|
ResourceOwnerPasswordAuthenticationToken resourceOwnerPasswordAuthenticationToken =
|
||||||
|
new ResourceOwnerPasswordAuthenticationToken(
|
||||||
|
clientPrincipal,
|
||||||
|
requestedScopes,
|
||||||
|
additionalParameters
|
||||||
|
);
|
||||||
|
return resourceOwnerPasswordAuthenticationToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static MultiValueMap<String, String> getParameters(HttpServletRequest request) {
|
||||||
|
Map<String, String[]> parameterMap = request.getParameterMap();
|
||||||
|
MultiValueMap<String, String> parameters = new LinkedMultiValueMap(parameterMap.size());
|
||||||
|
parameterMap.forEach((key, values) -> {
|
||||||
|
for (String value : values) {
|
||||||
|
parameters.add(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
return parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void throwError(String errorCode, String parameterName, String errorUri) {
|
||||||
|
OAuth2Error error = new OAuth2Error(errorCode, "OAuth 2.0 Parameter: " + parameterName, errorUri);
|
||||||
|
throw new OAuth2AuthenticationException(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,77 +1,167 @@
|
|||||||
package com.youlai.auth.authentication.wechat;
|
package com.youlai.auth.authentication.wechat;
|
||||||
|
|
||||||
import cn.binarywang.wx.miniapp.api.WxMaService;
|
import cn.hutool.core.lang.Assert;
|
||||||
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
|
import com.youlai.auth.authentication.password.ResourceOwnerPasswordAuthenticationToken;
|
||||||
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
import com.youlai.auth.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.dto.MemberAuthDTO;
|
|
||||||
import com.youlai.mall.ums.dto.MemberDTO;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.SneakyThrows;
|
|
||||||
import org.springframework.security.authentication.AuthenticationProvider;
|
import org.springframework.security.authentication.AuthenticationProvider;
|
||||||
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.AuthenticationException;
|
import org.springframework.security.core.AuthenticationException;
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
import org.springframework.security.oauth2.core.*;
|
||||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||||
|
import org.springframework.security.oauth2.core.oidc.endpoint.OidcParameterNames;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AccessTokenAuthenticationToken;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.context.AuthorizationServerContextHolder;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.token.DefaultOAuth2TokenContext;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenContext;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.security.Principal;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 微信认证提供者
|
* 微信认证提供者
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:xianrui0365@163.com">haoxr</a>
|
* @author haoxr
|
||||||
* @since 2021/9/25
|
* @since 3.0.0
|
||||||
*/
|
*/
|
||||||
@Data
|
@Slf4j
|
||||||
public class WechatAuthenticationProvider implements AuthenticationProvider {
|
public class WechatAuthenticationProvider implements AuthenticationProvider {
|
||||||
|
|
||||||
private UserDetailsService userDetailsService;
|
private static final String ERROR_URI = "https://datatracker.ietf.org/doc/html/rfc6749#section-5.2";
|
||||||
private WxMaService wxMaService;
|
|
||||||
private MemberFeignClient memberFeignClient;
|
|
||||||
|
|
||||||
/**
|
private final AuthenticationManager authenticationManager;
|
||||||
* 微信认证
|
private final OAuth2AuthorizationService authorizationService;
|
||||||
*
|
private final OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator;
|
||||||
* @param authentication
|
|
||||||
* @return
|
|
||||||
* @throws AuthenticationException
|
|
||||||
*/
|
|
||||||
@SneakyThrows
|
|
||||||
@Override
|
|
||||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
|
||||||
WechatAuthenticationToken authenticationToken = (WechatAuthenticationToken) authentication;
|
|
||||||
String code = (String) authenticationToken.getPrincipal();
|
|
||||||
|
|
||||||
WxMaJscode2SessionResult sessionInfo = wxMaService.getUserService().getSessionInfo(code);
|
/**
|
||||||
String openid = sessionInfo.getOpenid();
|
* Constructs an {@code OAuth2ResourceOwnerPasswordAuthenticationProviderNew} using the provided parameters.
|
||||||
Result<MemberAuthDTO> memberAuthResult = memberFeignClient.loadUserByOpenId(openid);
|
*
|
||||||
// 微信用户不存在,注册成为新会员
|
* @param authenticationManager the authentication manager
|
||||||
if (memberAuthResult != null && ResultCode.USER_NOT_EXIST.getCode().equals(memberAuthResult.getCode())) {
|
* @param authorizationService the authorization service
|
||||||
|
* @param tokenGenerator the token generator
|
||||||
String sessionKey = sessionInfo.getSessionKey();
|
* @since 0.2.3
|
||||||
String encryptedData = authenticationToken.getEncryptedData();
|
*/
|
||||||
String iv = authenticationToken.getIv();
|
public WechatAuthenticationProvider(AuthenticationManager authenticationManager,
|
||||||
// 解密 encryptedData 获取用户信息
|
OAuth2AuthorizationService authorizationService,
|
||||||
WxMaUserInfo userInfo = wxMaService.getUserService().getUserInfo(sessionKey, encryptedData, iv);
|
OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator
|
||||||
|
) {
|
||||||
MemberDTO memberDTO = new MemberDTO();
|
Assert.notNull(authorizationService, "authorizationService cannot be null");
|
||||||
BeanUtil.copyProperties(userInfo, memberDTO);
|
Assert.notNull(tokenGenerator, "tokenGenerator cannot be null");
|
||||||
memberDTO.setOpenid(openid);
|
this.authenticationManager = authenticationManager;
|
||||||
memberFeignClient.addMember(memberDTO);
|
this.authorizationService = authorizationService;
|
||||||
|
this.tokenGenerator = tokenGenerator;
|
||||||
}
|
}
|
||||||
UserDetails userDetails = ((MemberUserDetailsServiceImpl) userDetailsService).loadUserByOpenId(openid);
|
|
||||||
WechatAuthenticationToken result = new WechatAuthenticationToken(userDetails, new HashSet<>());
|
@Override
|
||||||
result.setDetails(authentication.getDetails());
|
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||||
return result;
|
|
||||||
}
|
ResourceOwnerPasswordAuthenticationToken authenticationToken = (ResourceOwnerPasswordAuthenticationToken) authentication;
|
||||||
|
|
||||||
|
// 验证客户端是否已认证
|
||||||
|
OAuth2ClientAuthenticationToken clientPrincipal = getAuthenticatedClientElseThrowInvalidClient(authenticationToken);
|
||||||
|
RegisteredClient registeredClient = clientPrincipal.getRegisteredClient();
|
||||||
|
|
||||||
|
// 验证客户端是否支持(grant_type=password)授权模式
|
||||||
|
if (!registeredClient.getAuthorizationGrantTypes().contains(AuthorizationGrantType.PASSWORD)) {
|
||||||
|
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.UNAUTHORIZED_CLIENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 密码验证
|
||||||
|
Map<String, Object> additionalParameters = authenticationToken.getAdditionalParameters();
|
||||||
|
String username = (String) additionalParameters.get("code");
|
||||||
|
String encryptedData = (String) additionalParameters.get("encryptedData");
|
||||||
|
String iv = (String) additionalParameters.get("iv");
|
||||||
|
UsernamePasswordAuthenticationToken passwordAuthenticationToken = new UsernamePasswordAuthenticationToken(username, password);
|
||||||
|
log.debug("got usernamePasswordAuthenticationToken=" + passwordAuthenticationToken);
|
||||||
|
Authentication usernamePasswordAuthentication = authenticationManager.authenticate(passwordAuthenticationToken);
|
||||||
|
|
||||||
|
usernamePasswordAuthentication.setAuthenticated(true);
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supports(Class<?> authentication) {
|
// 生成 access_token
|
||||||
return WechatAuthenticationToken.class.isAssignableFrom(authentication);
|
// @formatter:off
|
||||||
|
DefaultOAuth2TokenContext.Builder tokenContextBuilder = DefaultOAuth2TokenContext.builder()
|
||||||
|
.registeredClient(registeredClient)
|
||||||
|
.principal(usernamePasswordAuthentication)
|
||||||
|
.authorizationServerContext(AuthorizationServerContextHolder.getContext())
|
||||||
|
.authorizationGrantType(AuthorizationGrantType.PASSWORD)
|
||||||
|
.authorizationGrant(passwordAuthenticationToken);
|
||||||
|
// @formatter:on
|
||||||
|
|
||||||
|
// ----- Access token -----
|
||||||
|
OAuth2TokenContext tokenContext = tokenContextBuilder.tokenType(OAuth2TokenType.ACCESS_TOKEN).build();
|
||||||
|
OAuth2Token generatedAccessToken = this.tokenGenerator.generate(tokenContext);
|
||||||
|
if (generatedAccessToken == null) {
|
||||||
|
OAuth2Error error = new OAuth2Error(OAuth2ErrorCodes.SERVER_ERROR,
|
||||||
|
"The token generator failed to generate the access token.", ERROR_URI);
|
||||||
|
throw new OAuth2AuthenticationException(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
OAuth2AccessToken accessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,
|
||||||
|
generatedAccessToken.getTokenValue(), generatedAccessToken.getIssuedAt(),
|
||||||
|
generatedAccessToken.getExpiresAt(), tokenContext.getAuthorizedScopes());
|
||||||
|
|
||||||
|
// @formatter:off
|
||||||
|
OAuth2Authorization.Builder authorizationBuilder = OAuth2Authorization.withRegisteredClient(registeredClient)
|
||||||
|
.principalName(usernamePasswordAuthentication.getName())
|
||||||
|
.authorizationGrantType(AuthorizationGrantType.PASSWORD)
|
||||||
|
.attribute(Principal.class.getName(), usernamePasswordAuthentication);
|
||||||
|
// @formatter:on
|
||||||
|
if (generatedAccessToken instanceof ClaimAccessor) {
|
||||||
|
authorizationBuilder.token(accessToken, (metadata) ->
|
||||||
|
metadata.put(OAuth2Authorization.Token.CLAIMS_METADATA_NAME, ((ClaimAccessor) generatedAccessToken).getClaims()));
|
||||||
|
} else {
|
||||||
|
authorizationBuilder.accessToken(accessToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----- Refresh token -----
|
||||||
|
OAuth2RefreshToken refreshToken = null;
|
||||||
|
if (registeredClient.getAuthorizationGrantTypes().contains(AuthorizationGrantType.REFRESH_TOKEN) &&
|
||||||
|
// Do not issue refresh token to public client
|
||||||
|
!clientPrincipal.getClientAuthenticationMethod().equals(ClientAuthenticationMethod.NONE)) {
|
||||||
|
|
||||||
|
tokenContext = tokenContextBuilder.tokenType(OAuth2TokenType.REFRESH_TOKEN).build();
|
||||||
|
OAuth2Token generatedRefreshToken = this.tokenGenerator.generate(tokenContext);
|
||||||
|
if (!(generatedRefreshToken instanceof OAuth2RefreshToken)) {
|
||||||
|
OAuth2Error error = new OAuth2Error(OAuth2ErrorCodes.SERVER_ERROR,
|
||||||
|
"The token generator failed to generate the refresh token.", ERROR_URI);
|
||||||
|
throw new OAuth2AuthenticationException(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
refreshToken = (OAuth2RefreshToken) generatedRefreshToken;
|
||||||
|
authorizationBuilder.refreshToken(refreshToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
OAuth2Authorization authorization = authorizationBuilder.build();
|
||||||
|
this.authorizationService.save(authorization);
|
||||||
|
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, accessToken, refreshToken, additionalParameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supports(Class<?> authentication) {
|
||||||
|
return ResourceOwnerPasswordAuthenticationToken.class.isAssignableFrom(authentication);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static OAuth2ClientAuthenticationToken getAuthenticatedClientElseThrowInvalidClient(Authentication authentication) {
|
||||||
|
OAuth2ClientAuthenticationToken clientPrincipal = null;
|
||||||
|
if (OAuth2ClientAuthenticationToken.class.isAssignableFrom(authentication.getPrincipal().getClass())) {
|
||||||
|
clientPrincipal = (OAuth2ClientAuthenticationToken) authentication.getPrincipal();
|
||||||
|
}
|
||||||
|
if (clientPrincipal != null && clientPrincipal.isAuthenticated()) {
|
||||||
|
return clientPrincipal;
|
||||||
|
}
|
||||||
|
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_CLIENT);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@ -1,64 +1,51 @@
|
|||||||
package com.youlai.auth.authentication.wechat;
|
package com.youlai.auth.authentication.wechat;
|
||||||
|
|
||||||
|
import jakarta.annotation.Nullable;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||||
|
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationGrantAuthenticationToken;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.util.SpringAuthorizationServerVersion;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:xianrui0365@163.com">haoxr</a>
|
* 微信授权登录
|
||||||
* @since 2021/9/25
|
*
|
||||||
|
* @author haoxr
|
||||||
|
* @since 3.0.0
|
||||||
*/
|
*/
|
||||||
public class WechatAuthenticationToken extends AbstractAuthenticationToken {
|
public class WechatAuthenticationToken extends OAuth2AuthorizationGrantAuthenticationToken {
|
||||||
private static final long serialVersionUID = 550L;
|
|
||||||
private final Object principal;
|
private final Set<String> scopes;
|
||||||
@Getter
|
|
||||||
private String encryptedData;
|
|
||||||
@Getter
|
|
||||||
private String iv;
|
|
||||||
/**
|
|
||||||
* 账号校验之前的token构建
|
|
||||||
*
|
|
||||||
* @param principal
|
|
||||||
*/
|
|
||||||
public WechatAuthenticationToken(Object principal, String encryptedData,String iv) {
|
|
||||||
super(null);
|
|
||||||
this.principal = principal;
|
|
||||||
this.encryptedData = encryptedData;
|
|
||||||
this.iv=iv;
|
|
||||||
setAuthenticated(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 账号校验成功之后的token构建
|
* {@link org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientCredentialsAuthenticationToken}
|
||||||
*
|
*
|
||||||
* @param principal
|
* @param clientPrincipal
|
||||||
* @param authorities
|
* @param additionalParameters
|
||||||
*/
|
*/
|
||||||
public WechatAuthenticationToken(Object principal, Collection<? extends GrantedAuthority> authorities) {
|
public WechatAuthenticationToken(
|
||||||
super(authorities);
|
Authentication clientPrincipal,
|
||||||
this.principal = principal;
|
@Nullable Set<String> scopes,
|
||||||
super.setAuthenticated(true);
|
Map<String, Object> additionalParameters
|
||||||
|
) {
|
||||||
|
super(AuthorizationGrantType.PASSWORD, clientPrincipal, additionalParameters);
|
||||||
|
this.scopes = Collections.unmodifiableSet(scopes != null ? new HashSet<>(scopes) : Collections.emptySet());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<String> getScopes() {
|
||||||
|
return this.scopes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getCredentials() {
|
public Object getCredentials() {
|
||||||
return null;
|
return this.getAdditionalParameters().get(OAuth2ParameterNames.PASSWORD);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object getPrincipal() {
|
|
||||||
return this.principal;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
|
|
||||||
Assert.isTrue(!isAuthenticated, "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
|
|
||||||
super.setAuthenticated(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void eraseCredentials() {
|
|
||||||
super.eraseCredentials();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,66 +0,0 @@
|
|||||||
package com.youlai.auth.authentication.wechat;
|
|
||||||
|
|
||||||
import org.springframework.security.authentication.*;
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
|
|
||||||
import org.springframework.security.oauth2.provider.*;
|
|
||||||
import org.springframework.security.oauth2.provider.token.AbstractTokenGranter;
|
|
||||||
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
|
|
||||||
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 微信授权者
|
|
||||||
*
|
|
||||||
* @author <a href="mailto:xianrui0365@163.com">haoxr</a>
|
|
||||||
* @since 2021/9/25
|
|
||||||
*/
|
|
||||||
public class WechatTokenGranter extends AbstractTokenGranter {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 声明授权者 WechatTokenGranter 支持授权模式 wechat
|
|
||||||
* 根据接口传值 grant_type = wechat 的值匹配到此授权者
|
|
||||||
* 匹配逻辑详见下面的两个方法
|
|
||||||
*
|
|
||||||
* @see org.springframework.security.oauth2.provider.CompositeTokenGranter#grant(String, TokenRequest)
|
|
||||||
* @see org.springframework.security.oauth2.provider.token.AbstractTokenGranter#grant(String, TokenRequest)
|
|
||||||
*/
|
|
||||||
private static final String GRANT_TYPE = "wechat";
|
|
||||||
private final AuthenticationManager authenticationManager;
|
|
||||||
|
|
||||||
public WechatTokenGranter(AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory, AuthenticationManager authenticationManager) {
|
|
||||||
super(tokenServices, clientDetailsService, requestFactory, GRANT_TYPE);
|
|
||||||
this.authenticationManager = authenticationManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) {
|
|
||||||
|
|
||||||
Map<String, String> parameters = new LinkedHashMap(tokenRequest.getRequestParameters());
|
|
||||||
String code = parameters.get("code");
|
|
||||||
String encryptedData = parameters.get("encryptedData");
|
|
||||||
String iv = parameters.get("iv");
|
|
||||||
|
|
||||||
// 移除后续无用参数
|
|
||||||
parameters.remove("code");
|
|
||||||
parameters.remove("encryptedData");
|
|
||||||
parameters.remove("iv");
|
|
||||||
|
|
||||||
Authentication userAuth = new WechatAuthenticationToken(code, encryptedData,iv); // 未认证状态
|
|
||||||
((AbstractAuthenticationToken) userAuth).setDetails(parameters);
|
|
||||||
|
|
||||||
try {
|
|
||||||
userAuth = this.authenticationManager.authenticate(userAuth); // 认证中
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new InvalidGrantException(e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (userAuth != null && userAuth.isAuthenticated()) { // 认证成功
|
|
||||||
OAuth2Request storedOAuth2Request = this.getRequestFactory().createOAuth2Request(client, tokenRequest);
|
|
||||||
return new OAuth2Authentication(storedOAuth2Request, userAuth);
|
|
||||||
} else { // 认证失败
|
|
||||||
throw new InvalidGrantException("Could not authenticate code: " + code);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user