init
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
package com.newyetai.security.social.service;
|
||||
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration.Builder;
|
||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
|
||||
|
||||
import com.newyetai.security.ssb.SsbAuthenticationFilter;
|
||||
import com.newyetai.usercenter.auth.constant.AuthTypeEnum;
|
||||
|
||||
public enum CommonOAuth2Provider {
|
||||
|
||||
WECHAT {
|
||||
|
||||
@Override
|
||||
public Builder getBuilder(String registrationId) {
|
||||
ClientRegistration.Builder builder = getBuilder(registrationId,
|
||||
ClientAuthenticationMethod.BASIC, DEFAULT_REDIRECT_URL);
|
||||
builder.scope("snsapi_userinfo");
|
||||
builder.authorizationUri("https://open.weixin.qq.com/connect/oauth2/authorize");
|
||||
builder.tokenUri("https://api.weixin.qq.com/sns/oauth2/access_token");
|
||||
builder.userInfoUri("https://api.weixin.qq.com/sns/userinfo");
|
||||
builder.userNameAttributeName("openid");
|
||||
builder.clientName(AuthTypeEnum.WECHAT.name());
|
||||
builder.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE);
|
||||
return builder;
|
||||
}
|
||||
},
|
||||
|
||||
SSBAPP {
|
||||
|
||||
@Override
|
||||
public Builder getBuilder(String registrationId) {
|
||||
ClientRegistration.Builder builder = getBuilder(registrationId,
|
||||
ClientAuthenticationMethod.BASIC, DEFAULT_REDIRECT_URL);
|
||||
builder.authorizationUri("https://api.eshimin.com/newOauth/authorize");
|
||||
builder.tokenUri("https://api.eshimin.com/newOauth/accessToken");
|
||||
builder.userInfoUri("https://api.eshimin.com/newOauth/userInfo");
|
||||
builder.clientName(AuthTypeEnum.SSB_APP.name());
|
||||
builder.scope("read");
|
||||
builder.redirectUriTemplate("{baseUrl}/" + SsbAuthenticationFilter.LOGIN_URI);
|
||||
builder.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE);
|
||||
return builder;
|
||||
}
|
||||
},
|
||||
|
||||
WECHAT_LITE {
|
||||
|
||||
@Override
|
||||
public Builder getBuilder(String registrationId) {
|
||||
ClientRegistration.Builder builder = getBuilder(registrationId,
|
||||
ClientAuthenticationMethod.BASIC, DEFAULT_REDIRECT_URL);
|
||||
builder.clientName(AuthTypeEnum.WECHAT_LITE.name());
|
||||
return builder;
|
||||
}
|
||||
},
|
||||
|
||||
ALIPAY {
|
||||
|
||||
@Override
|
||||
public Builder getBuilder(String registrationId) {
|
||||
ClientRegistration.Builder builder = getBuilder(registrationId,
|
||||
ClientAuthenticationMethod.POST, DEFAULT_REDIRECT_URL);
|
||||
builder.clientName(AuthTypeEnum.ALIPAY.name());
|
||||
return builder;
|
||||
}
|
||||
},
|
||||
|
||||
ALIPAY_LITE {
|
||||
|
||||
@Override
|
||||
public Builder getBuilder(String registrationId) {
|
||||
ClientRegistration.Builder builder = getBuilder(registrationId,
|
||||
ClientAuthenticationMethod.BASIC, DEFAULT_REDIRECT_URL);
|
||||
builder.clientName(AuthTypeEnum.ALIPAY_LITE.name());
|
||||
return builder;
|
||||
}
|
||||
},
|
||||
|
||||
;
|
||||
|
||||
|
||||
private static final String DEFAULT_REDIRECT_URL =
|
||||
"{baseUrl}/{action}/oauth2/code/{registrationId}";
|
||||
|
||||
protected final ClientRegistration.Builder getBuilder(String registrationId,
|
||||
ClientAuthenticationMethod method, String redirectUri) {
|
||||
ClientRegistration.Builder builder = ClientRegistration.withRegistrationId(registrationId);
|
||||
builder.clientAuthenticationMethod(method);
|
||||
builder.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE);
|
||||
builder.redirectUriTemplate(redirectUri);
|
||||
return builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new
|
||||
* {@link org.springframework.security.oauth2.client.registration.ClientRegistration.Builder
|
||||
* ClientRegistration.Builder} pre-configured with provider defaults.
|
||||
* @param registrationId the registration-id used with the new builder
|
||||
* @return a builder instance
|
||||
*/
|
||||
public abstract ClientRegistration.Builder getBuilder(String registrationId);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package com.newyetai.security.social.service;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.http.RequestEntity;
|
||||
import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest;
|
||||
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
|
||||
import org.springframework.security.oauth2.core.user.OAuth2User;
|
||||
|
||||
public interface IOauthProvider {
|
||||
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* 修改默认auth的请求地址
|
||||
*
|
||||
* @param request
|
||||
* @param authorizationRequest
|
||||
* @return
|
||||
* @author sr on 2021-06-28
|
||||
*/
|
||||
default OAuth2AuthorizationRequest decorateRequest(HttpServletRequest request,
|
||||
OAuth2AuthorizationRequest authorizationRequest) {
|
||||
return authorizationRequest;
|
||||
}
|
||||
|
||||
default OAuth2AccessTokenResponse getTokenResponse(
|
||||
OAuth2AuthorizationCodeGrantRequest authorizationCodeGrantRequest) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取token转换器(无则OAuth2AuthorizationCodeGrantRequestEntityConverter)
|
||||
* @return
|
||||
* @author sr on 2021-06-28
|
||||
*/
|
||||
default Converter<OAuth2AuthorizationCodeGrantRequest, RequestEntity<?>> getTokenConvert(){
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户转换器(无则OAuth2UserRequestEntityConverter)
|
||||
* @return
|
||||
* @author sr on 2021-06-28
|
||||
*/
|
||||
default Converter<OAuth2UserRequest, RequestEntity<?>> getUserConvert(){
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 处理第三方用户信息,获取登录用户
|
||||
* @param userRequest
|
||||
* @param userJsonStr
|
||||
* @return
|
||||
* @author sr on 2021-06-28
|
||||
*/
|
||||
default OAuth2User dealUser(OAuth2UserRequest userRequest, String userJsonStr) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package com.newyetai.security.social.service;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientProperties;
|
||||
import org.springframework.boot.context.properties.PropertyMapper;
|
||||
import org.springframework.boot.convert.ApplicationConversionService;
|
||||
import org.springframework.core.convert.ConversionException;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration.Builder;
|
||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.newyetai.common.exception.util.Assert;
|
||||
import com.newyetai.common.util.JsonUtils;
|
||||
import com.newyetai.usercenter.auth.constant.AuthTypeEnum;
|
||||
import com.newyetai.usercenter.auth.dto.AuthClientDTO;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class OAuth2ClientRegistrationAdapter {
|
||||
|
||||
private static Map<String, CommonOAuth2Provider> providers = Maps.newConcurrentMap();
|
||||
|
||||
private OAuth2ClientRegistrationAdapter() {}
|
||||
|
||||
public static ClientRegistration getClientRegistration(String registrationId,
|
||||
AuthTypeEnum authTypeEnum,
|
||||
AuthClientDTO authClientDTO) {
|
||||
Assert.isTrue(authTypeEnum != null, new IllegalArgumentException("非法授权标识"));
|
||||
OAuth2ClientProperties.Registration registration =
|
||||
JsonUtils.toObject(authClientDTO.getParamData(), OAuth2ClientProperties.Registration.class);
|
||||
return getClientRegistration(registrationId, authTypeEnum, registration);
|
||||
}
|
||||
|
||||
private static ClientRegistration getClientRegistration(String registrationId,
|
||||
AuthTypeEnum authTypeEnum,
|
||||
OAuth2ClientProperties.Registration registration) {
|
||||
Assert.isTrue(authTypeEnum != null, new IllegalArgumentException("非法授权标识"));
|
||||
Builder builder = getBuilder(authTypeEnum.name()).getBuilder(registrationId);
|
||||
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
|
||||
map.from(registration::getClientId).to(builder::clientId);
|
||||
map.from(registration::getClientSecret).to(builder::clientSecret);
|
||||
map.from(registration::getClientAuthenticationMethod).as(ClientAuthenticationMethod::new)
|
||||
.to(builder::clientAuthenticationMethod);
|
||||
map.from(registration::getAuthorizationGrantType).as(AuthorizationGrantType::new)
|
||||
.to(builder::authorizationGrantType);
|
||||
map.from(registration::getRedirectUri).to(builder::redirectUriTemplate);
|
||||
map.from(registration::getScope).as((scope) -> StringUtils.toStringArray(scope))
|
||||
.to(builder::scope);
|
||||
map.from(registration::getClientName).to(builder::clientName);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public static CommonOAuth2Provider getBuilder(String authTypeName) {
|
||||
CommonOAuth2Provider provider = providers.get(authTypeName);
|
||||
if (provider == null) {
|
||||
try {
|
||||
provider =
|
||||
ApplicationConversionService.getSharedInstance().convert(authTypeName,
|
||||
CommonOAuth2Provider.class);
|
||||
providers.put(authTypeName, provider);
|
||||
} catch (ConversionException ex) {
|
||||
log.error("授权类型标识错误,未找到对应的oauth2提供者:{}", authTypeName);
|
||||
throw new IllegalArgumentException("授权类型标识错误,未找到对应的oauth2提供者:" + authTypeName, ex);
|
||||
}
|
||||
}
|
||||
return provider;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package com.newyetai.security.social.service;
|
||||
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.http.RequestEntity;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.converter.FormHttpMessageConverter;
|
||||
import org.springframework.http.converter.StringHttpMessageConverter;
|
||||
import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient;
|
||||
import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest;
|
||||
import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequestEntityConverter;
|
||||
import org.springframework.security.oauth2.client.http.OAuth2ErrorResponseErrorHandler;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthorizationException;
|
||||
import org.springframework.security.oauth2.core.OAuth2Error;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
|
||||
import org.springframework.security.oauth2.core.http.converter.OAuth2AccessTokenResponseHttpMessageConverter;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.web.client.RestClientException;
|
||||
import org.springframework.web.client.RestOperations;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import com.newyetai.security.social.util.Oauth2ProviderUtils;
|
||||
|
||||
/**
|
||||
* code获取token
|
||||
*
|
||||
* @author sr on 2021-01-12
|
||||
*/
|
||||
public class StandardAuthorizationCodeTokenResponseClient
|
||||
implements OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> {
|
||||
public static final String INVALID_TOKEN_RESPONSE_ERROR_CODE = "invalid_token_response";
|
||||
public static final RestOperations restOperations;
|
||||
|
||||
private Converter<OAuth2AuthorizationCodeGrantRequest, RequestEntity<?>> requestEntityConverter =
|
||||
new OAuth2AuthorizationCodeGrantRequestEntityConverter();
|
||||
|
||||
static {
|
||||
RestTemplate restTemplate = new RestTemplate(Arrays.asList(
|
||||
new FormHttpMessageConverter(), new OAuth2AccessTokenResponseHttpMessageConverter(),
|
||||
new StringHttpMessageConverter()));
|
||||
restTemplate.setErrorHandler(new OAuth2ErrorResponseErrorHandler());
|
||||
restOperations = restTemplate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuth2AccessTokenResponse getTokenResponse(
|
||||
OAuth2AuthorizationCodeGrantRequest authorizationCodeGrantRequest) {
|
||||
|
||||
Assert.notNull(authorizationCodeGrantRequest, "authorizationCodeGrantRequest cannot be null");
|
||||
|
||||
// 不同类型不同请求体
|
||||
OAuth2AccessTokenResponse tokenResponse = Oauth2ProviderUtils
|
||||
.getProvider(authorizationCodeGrantRequest.getClientRegistration().getClientName())
|
||||
.getTokenResponse(authorizationCodeGrantRequest);
|
||||
|
||||
if (tokenResponse != null) {
|
||||
return tokenResponse;
|
||||
}
|
||||
|
||||
RequestEntity<?> request = this.requestEntityConverter.convert(authorizationCodeGrantRequest);
|
||||
|
||||
ResponseEntity<OAuth2AccessTokenResponse> response;
|
||||
try {
|
||||
response = restOperations.exchange(request, OAuth2AccessTokenResponse.class);
|
||||
} catch (RestClientException ex) {
|
||||
OAuth2Error oauth2Error = new OAuth2Error(INVALID_TOKEN_RESPONSE_ERROR_CODE,
|
||||
"An error occurred while attempting to retrieve the OAuth 2.0 Access Token Response: "
|
||||
+ ex.getMessage(),
|
||||
null);
|
||||
throw new OAuth2AuthorizationException(oauth2Error, ex);
|
||||
}
|
||||
|
||||
tokenResponse = response.getBody();
|
||||
|
||||
if (CollectionUtils.isEmpty(tokenResponse.getAccessToken().getScopes())) {
|
||||
// As per spec, in Section 5.1 Successful Access Token Response
|
||||
// https://tools.ietf.org/html/rfc6749#section-5.1
|
||||
// If AccessTokenResponse.scope is empty, then default to the scope
|
||||
// originally requested by the client in the Token Request
|
||||
tokenResponse = OAuth2AccessTokenResponse.withResponse(tokenResponse)
|
||||
.scopes(authorizationCodeGrantRequest.getClientRegistration().getScopes())
|
||||
.build();
|
||||
}
|
||||
|
||||
return tokenResponse;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link Converter} used for converting the {@link OAuth2AuthorizationCodeGrantRequest}
|
||||
* to a {@link RequestEntity} representation of the OAuth 2.0 Access Token Request.
|
||||
*
|
||||
* @param requestEntityConverter the {@link Converter} used for converting to a {@link RequestEntity} representation of the Access Token Request
|
||||
*/
|
||||
public void setRequestEntityConverter(
|
||||
Converter<OAuth2AuthorizationCodeGrantRequest, RequestEntity<?>> requestEntityConverter) {
|
||||
Assert.notNull(requestEntityConverter, "requestEntityConverter cannot be null");
|
||||
this.requestEntityConverter = requestEntityConverter;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.newyetai.security.social.service;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
|
||||
|
||||
import com.newyetai.common.exception.util.Assert;
|
||||
import com.newyetai.usercenter.auth.constant.AuthTypeEnum;
|
||||
import com.newyetai.usercenter.auth.dto.AuthClientDTO;
|
||||
import com.newyetai.usercenter.auth.dto.AuthClientQueryDTO;
|
||||
import com.newyetai.usercenter.user.login.service.UserLoginService;
|
||||
|
||||
public class StandardClientRegistrationRepository implements ClientRegistrationRepository {
|
||||
|
||||
private UserLoginService userLoginService;
|
||||
|
||||
public StandardClientRegistrationRepository(UserLoginService userLoginService) {
|
||||
this.userLoginService = userLoginService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientRegistration findByRegistrationId(String registrationId) {
|
||||
Assert.isTrue(StringUtils.isNotBlank(registrationId),
|
||||
new IllegalArgumentException("oauth授权注册标识不能为空"));
|
||||
AuthClientDTO authClientDTO = userLoginService
|
||||
.findAuthClientDTO(AuthClientQueryDTO.builder().id(Long.valueOf(registrationId)).build());
|
||||
AuthTypeEnum authTypeEnum = AuthTypeEnum.getByCode(authClientDTO.getAuthTypeCode());
|
||||
return OAuth2ClientRegistrationAdapter.getClientRegistration(authClientDTO.getId().toString(),
|
||||
authTypeEnum, authClientDTO);
|
||||
}
|
||||
|
||||
public ClientRegistration findByRegistrationId(String authTypeName, String domainOrIp) {
|
||||
AuthTypeEnum authTypeEnum = AuthTypeEnum.valueOf(authTypeName.toUpperCase());
|
||||
return this.findByRegistrationId(authTypeEnum, domainOrIp);
|
||||
}
|
||||
|
||||
public ClientRegistration findByRegistrationId(Integer authTypeCode, String domainOrIp) {
|
||||
AuthTypeEnum authTypeEnum = AuthTypeEnum.getByCode(authTypeCode);
|
||||
return this.findByRegistrationId(authTypeEnum, domainOrIp);
|
||||
}
|
||||
|
||||
private ClientRegistration findByRegistrationId(AuthTypeEnum authTypeEnum, String domainOrIp) {
|
||||
AuthClientDTO authClientDTO = userLoginService.findAuthClientDTO(
|
||||
AuthClientQueryDTO.builder().domainOrIp(domainOrIp).authTypeCode(authTypeEnum.getCode())
|
||||
.build());
|
||||
return OAuth2ClientRegistrationAdapter.getClientRegistration(authClientDTO.getId().toString(),
|
||||
authTypeEnum, authClientDTO);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package com.newyetai.security.social.service;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.http.RequestEntity;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.oauth2.client.http.OAuth2ErrorResponseErrorHandler;
|
||||
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
|
||||
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequestEntityConverter;
|
||||
import org.springframework.security.oauth2.client.userinfo.OAuth2UserService;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthorizationException;
|
||||
import org.springframework.security.oauth2.core.OAuth2Error;
|
||||
import org.springframework.security.oauth2.core.user.OAuth2User;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.client.RestClientException;
|
||||
import org.springframework.web.client.RestOperations;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import com.newyetai.security.social.util.Oauth2ProviderUtils;
|
||||
|
||||
public class StandardOAuth2UserService implements OAuth2UserService<OAuth2UserRequest, OAuth2User> {
|
||||
|
||||
private static final String MISSING_USER_INFO_URI_ERROR_CODE = "missing_user_info_uri";
|
||||
|
||||
private static final String MISSING_USER_NAME_ATTRIBUTE_ERROR_CODE =
|
||||
"missing_user_name_attribute";
|
||||
|
||||
private static final String INVALID_USER_INFO_RESPONSE_ERROR_CODE = "invalid_user_info_response";
|
||||
|
||||
private Converter<OAuth2UserRequest, RequestEntity<?>> requestEntityConverter =
|
||||
new OAuth2UserRequestEntityConverter();
|
||||
|
||||
private RestOperations restOperations;
|
||||
|
||||
public StandardOAuth2UserService() {
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
restTemplate.setErrorHandler(new OAuth2ErrorResponseErrorHandler());
|
||||
this.restOperations = restTemplate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
|
||||
Assert.notNull(userRequest, "userRequest cannot be null");
|
||||
|
||||
if (!StringUtils.hasText(
|
||||
userRequest.getClientRegistration().getProviderDetails().getUserInfoEndpoint().getUri())) {
|
||||
OAuth2Error oauth2Error = new OAuth2Error(MISSING_USER_INFO_URI_ERROR_CODE,
|
||||
"Missing required UserInfo Uri in UserInfoEndpoint for Client Registration: "
|
||||
+ userRequest.getClientRegistration().getRegistrationId(),
|
||||
null);
|
||||
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
|
||||
}
|
||||
|
||||
String userNameAttributeName = userRequest.getClientRegistration().getProviderDetails()
|
||||
.getUserInfoEndpoint().getUserNameAttributeName();
|
||||
if (!StringUtils.hasText(userNameAttributeName)) {
|
||||
OAuth2Error oauth2Error = new OAuth2Error(MISSING_USER_NAME_ATTRIBUTE_ERROR_CODE,
|
||||
"Missing required \"user name\" attribute name in UserInfoEndpoint for Client Registration: "
|
||||
+ userRequest.getClientRegistration().getRegistrationId(),
|
||||
null);
|
||||
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
|
||||
}
|
||||
|
||||
IOauthProvider provider = Oauth2ProviderUtils
|
||||
.getProvider(userRequest.getClientRegistration().getClientName());
|
||||
// 不同类型不同请求体
|
||||
Converter<OAuth2UserRequest, RequestEntity<?>> converter =
|
||||
provider.getUserConvert();
|
||||
if (converter == null) {
|
||||
converter = requestEntityConverter;
|
||||
}
|
||||
|
||||
// 获得request
|
||||
RequestEntity<?> request = converter.convert(userRequest);
|
||||
|
||||
ResponseEntity<String> response;
|
||||
try {
|
||||
// 执行request
|
||||
response = this.restOperations.exchange(request, String.class);
|
||||
} catch (OAuth2AuthorizationException ex) {
|
||||
OAuth2Error oauth2Error = ex.getError();
|
||||
StringBuilder errorDetails = new StringBuilder();
|
||||
errorDetails.append("Error details: [");
|
||||
errorDetails.append("UserInfo Uri: ").append(
|
||||
userRequest.getClientRegistration().getProviderDetails().getUserInfoEndpoint().getUri());
|
||||
errorDetails.append(", Error Code: ").append(oauth2Error.getErrorCode());
|
||||
if (oauth2Error.getDescription() != null) {
|
||||
errorDetails.append(", Error Description: ").append(oauth2Error.getDescription());
|
||||
}
|
||||
errorDetails.append("]");
|
||||
oauth2Error = new OAuth2Error(INVALID_USER_INFO_RESPONSE_ERROR_CODE,
|
||||
"An error occurred while attempting to retrieve the UserInfo Resource: "
|
||||
+ errorDetails.toString(),
|
||||
null);
|
||||
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString(), ex);
|
||||
} catch (RestClientException ex) {
|
||||
OAuth2Error oauth2Error = new OAuth2Error(INVALID_USER_INFO_RESPONSE_ERROR_CODE,
|
||||
"An error occurred while attempting to retrieve the UserInfo Resource: "
|
||||
+ ex.getMessage(),
|
||||
null);
|
||||
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString(), ex);
|
||||
}
|
||||
|
||||
// 解析response
|
||||
String userAttributes = response.getBody();
|
||||
return provider.dealUser(userRequest, userAttributes);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
package com.newyetai.security.social.service;
|
||||
|
||||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.security.crypto.keygen.Base64StringKeyGenerator;
|
||||
import org.springframework.security.crypto.keygen.StringKeyGenerator;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
|
||||
import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter;
|
||||
import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestResolver;
|
||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||
import org.springframework.security.web.util.UrlUtils;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
import com.newyetai.common.util.RequestUtils;
|
||||
import com.newyetai.security.social.util.Oauth2ProviderUtils;
|
||||
import com.newyetai.usercenter.constants.SecurityConstants;
|
||||
import com.newyetai.usercenter.user.constant.UserTypeEnum;
|
||||
|
||||
/**
|
||||
* An implementation of an {@link OAuth2AuthorizationRequestResolver} that attempts to
|
||||
* resolve an {@link OAuth2AuthorizationRequest} from the provided {@code HttpServletRequest}
|
||||
* using the default request {@code URI} pattern {@code /oauth2/authorization/{registrationId}}.
|
||||
*
|
||||
* <p>
|
||||
* <b>NOTE:</b> The default base {@code URI} {@code /oauth2/authorization} may be overridden
|
||||
* via it's constructor {@link #DefaultOAuth2AuthorizationRequestResolver(ClientRegistrationRepository, String)}.
|
||||
*
|
||||
* @author Joe Grandja
|
||||
* @author Rob Winch
|
||||
* @since 5.1
|
||||
* @see OAuth2AuthorizationRequestResolver
|
||||
* @see OAuth2AuthorizationRequestRedirectFilter
|
||||
*/
|
||||
public final class StandardOauth2AuthorizationRequestResolver
|
||||
implements OAuth2AuthorizationRequestResolver {
|
||||
private static final String REGISTRATION_ID_URI_VARIABLE_NAME = "registrationId";
|
||||
private final ClientRegistrationRepository clientRegistrationRepository;
|
||||
private final AntPathRequestMatcher authorizationRequestMatcher;
|
||||
private final StringKeyGenerator stateGenerator =
|
||||
new Base64StringKeyGenerator(Base64.getUrlEncoder());
|
||||
|
||||
/**
|
||||
* Constructs a {@code DefaultOAuth2AuthorizationRequestResolver} using the provided parameters.
|
||||
*
|
||||
* @param clientRegistrationRepository the repository of client registrations
|
||||
* @param authorizationRequestBaseUri the base {@code URI} used for resolving authorization requests
|
||||
*/
|
||||
public StandardOauth2AuthorizationRequestResolver(
|
||||
// StandardClientRegistrationRepository standardClientRegistrationRepository,
|
||||
ClientRegistrationRepository standardClientRegistrationRepository,
|
||||
String authorizationRequestBaseUri) {
|
||||
Assert.notNull(standardClientRegistrationRepository,
|
||||
"clientRegistrationRepository cannot be null");
|
||||
Assert.hasText(authorizationRequestBaseUri, "authorizationRequestBaseUri cannot be empty");
|
||||
this.clientRegistrationRepository = standardClientRegistrationRepository;
|
||||
this.authorizationRequestMatcher = new AntPathRequestMatcher(
|
||||
authorizationRequestBaseUri + "/{" + REGISTRATION_ID_URI_VARIABLE_NAME + "}");
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuth2AuthorizationRequest resolve(HttpServletRequest request) {
|
||||
String registrationId = this.resolveRegistrationId(request);
|
||||
String redirectUriAction = getAction(request, "login");
|
||||
return resolve(request, registrationId, redirectUriAction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuth2AuthorizationRequest resolve(HttpServletRequest request, String registrationId) {
|
||||
if (registrationId == null) {
|
||||
return null;
|
||||
}
|
||||
String redirectUriAction = getAction(request, "authorize");
|
||||
return resolve(request, registrationId, redirectUriAction);
|
||||
}
|
||||
|
||||
private String getAction(HttpServletRequest request, String defaultAction) {
|
||||
String action = request.getParameter("action");
|
||||
if (action == null) {
|
||||
return defaultAction;
|
||||
}
|
||||
return action;
|
||||
}
|
||||
|
||||
private OAuth2AuthorizationRequest resolve(HttpServletRequest request, String registrationId,
|
||||
String redirectUriAction) {
|
||||
if (registrationId == null) {
|
||||
return null;
|
||||
}
|
||||
String domainOrIp = RequestUtils.getDomain(request);
|
||||
ClientRegistration clientRegistration = null;
|
||||
if (clientRegistrationRepository instanceof StandardClientRegistrationRepository) {
|
||||
clientRegistration =
|
||||
((StandardClientRegistrationRepository) this.clientRegistrationRepository)
|
||||
.findByRegistrationId(registrationId, domainOrIp);
|
||||
} else {
|
||||
clientRegistration = this.clientRegistrationRepository.findByRegistrationId(registrationId);
|
||||
}
|
||||
|
||||
if (clientRegistration == null) {
|
||||
throw new IllegalArgumentException("Invalid Client Registration with Id: " + registrationId);
|
||||
}
|
||||
|
||||
OAuth2AuthorizationRequest.Builder builder;
|
||||
if (AuthorizationGrantType.AUTHORIZATION_CODE
|
||||
.equals(clientRegistration.getAuthorizationGrantType())) {
|
||||
builder = OAuth2AuthorizationRequest.authorizationCode();
|
||||
} else if (AuthorizationGrantType.IMPLICIT
|
||||
.equals(clientRegistration.getAuthorizationGrantType())) {
|
||||
builder = OAuth2AuthorizationRequest.implicit();
|
||||
} else {
|
||||
throw new IllegalArgumentException("Invalid Authorization Grant Type (" +
|
||||
clientRegistration.getAuthorizationGrantType().getValue() +
|
||||
") for Client Registration with Id: " + clientRegistration.getRegistrationId());
|
||||
}
|
||||
|
||||
String redirectUriStr = this.expandRedirectUri(request, clientRegistration, redirectUriAction);
|
||||
|
||||
Map<String, Object> additionalParameters = new HashMap<>();
|
||||
additionalParameters.put(OAuth2ParameterNames.REGISTRATION_ID,
|
||||
clientRegistration.getRegistrationId());
|
||||
String userType = request.getParameter(SecurityConstants.LOGIN_USER_TYPE_KEY);
|
||||
String registerCode = request.getParameter(SecurityConstants.LOGIN_REGISTER_CODE_KEY);
|
||||
String entrypoint = request.getParameter(SecurityConstants.LOGIN_ENTRYPOINT_KEY);
|
||||
if (StringUtils.isBlank(userType)) {
|
||||
userType = UserTypeEnum.PERSON.getType().toString();
|
||||
}
|
||||
additionalParameters.put(SecurityConstants.LOGIN_USER_TYPE_KEY, userType);
|
||||
if (StringUtils.isNotBlank(registerCode)) {
|
||||
additionalParameters.put(SecurityConstants.LOGIN_REGISTER_CODE_KEY, registerCode);
|
||||
}
|
||||
if (StringUtils.isNotBlank(entrypoint)) {
|
||||
additionalParameters.put(SecurityConstants.LOGIN_ENTRYPOINT_KEY, entrypoint);
|
||||
}
|
||||
|
||||
OAuth2AuthorizationRequest authorizationRequest = builder
|
||||
.clientId(clientRegistration.getClientId())
|
||||
.authorizationUri(clientRegistration.getProviderDetails().getAuthorizationUri())
|
||||
.redirectUri(redirectUriStr)
|
||||
.scopes(clientRegistration.getScopes())
|
||||
.state(this.stateGenerator.generateKey())
|
||||
.additionalParameters(additionalParameters)
|
||||
.build();
|
||||
// 不同授权需要额外修饰
|
||||
IOauthProvider oauthProvider = Oauth2ProviderUtils.getProvider(registrationId);
|
||||
if (oauthProvider != null) {
|
||||
return oauthProvider.decorateRequest(request, authorizationRequest);
|
||||
}
|
||||
return authorizationRequest;
|
||||
}
|
||||
|
||||
private String resolveRegistrationId(HttpServletRequest request) {
|
||||
if (this.authorizationRequestMatcher.matches(request)) {
|
||||
return this.authorizationRequestMatcher
|
||||
.extractUriTemplateVariables(request).get(REGISTRATION_ID_URI_VARIABLE_NAME);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String expandRedirectUri(HttpServletRequest request,
|
||||
ClientRegistration clientRegistration, String action) {
|
||||
// Supported URI variables -> baseUrl, action, registrationId
|
||||
// Used in -> CommonOAuth2Provider.DEFAULT_REDIRECT_URL = "{baseUrl}/{action}/oauth2/code/{registrationId}"
|
||||
Map<String, String> uriVariables = new HashMap<>();
|
||||
uriVariables.put("registrationId", clientRegistration.getRegistrationId());
|
||||
String baseUrl = UriComponentsBuilder.fromHttpUrl(UrlUtils.buildFullRequestUrl(request))
|
||||
.replaceQuery(null)
|
||||
.replacePath(request.getContextPath())
|
||||
.build()
|
||||
.toUriString();
|
||||
uriVariables.put("baseUrl", baseUrl);
|
||||
if (action != null) {
|
||||
uriVariables.put("action", action);
|
||||
}
|
||||
return UriComponentsBuilder.fromUriString(clientRegistration.getRedirectUriTemplate())
|
||||
.buildAndExpand(uriVariables)
|
||||
.toUriString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.newyetai.security.social.ssb.service;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.newyetai.sdk.ssb.SsbProperties;
|
||||
import com.newyetai.sdk.ssb.util.SM2Utils;
|
||||
import com.newyetai.security.social.service.IOauthProvider;
|
||||
import com.newyetai.security.util.SecurityUtils;
|
||||
import com.newyetai.usercenter.auth.constant.AuthTypeEnum;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class SsbOauthLoginProvider implements IOauthProvider {
|
||||
|
||||
private static final String AUTH_URL =
|
||||
"https://api.eshimin.com/newOauth/authorize?client_id=%s&response_type=authorization_code&scope=read&redirect_uri=%s×tamp=%s&sign=%s&state=%s";
|
||||
|
||||
@Autowired
|
||||
private SsbProperties ssbProperties;
|
||||
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return AuthTypeEnum.SSB_APP.name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuth2AuthorizationRequest decorateRequest(HttpServletRequest request,
|
||||
OAuth2AuthorizationRequest authorizationRequest) {
|
||||
String timestamp = String.valueOf(System.currentTimeMillis());
|
||||
String sign = SM2Utils.sign(ssbProperties.getSm2PrivateKey(),
|
||||
ssbProperties.getAppKey() + ssbProperties.getAppSecret() + timestamp,
|
||||
ssbProperties.getAppKey());
|
||||
|
||||
// 指定成功跳转地址
|
||||
String redirectUrl =
|
||||
SecurityUtils.dealRedirectUrl(request, authorizationRequest.getRedirectUri());
|
||||
|
||||
String state = "123";
|
||||
|
||||
// 微信Authorization Request URL
|
||||
String authorizationRequestUri =
|
||||
String.format(AUTH_URL,
|
||||
authorizationRequest.getClientId(),
|
||||
SecurityUtils.encodeURL(redirectUrl),
|
||||
timestamp,
|
||||
sign,
|
||||
state);
|
||||
|
||||
return OAuth2AuthorizationRequest.from(authorizationRequest)
|
||||
.authorizationRequestUri(authorizationRequestUri)
|
||||
.build();
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.newyetai.security.social.util;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.collections4.map.CaseInsensitiveMap;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.newyetai.common.exception.util.Assert;
|
||||
import com.newyetai.security.social.service.IOauthProvider;
|
||||
|
||||
@Component
|
||||
public class Oauth2ProviderUtils {
|
||||
|
||||
private static Map<String, IOauthProvider> providerMap = new CaseInsensitiveMap<String, IOauthProvider>();
|
||||
|
||||
private Oauth2ProviderUtils(List<IOauthProvider> providers) {
|
||||
providers.forEach(provider -> providerMap.put(provider.getName(), provider));
|
||||
}
|
||||
|
||||
public static IOauthProvider getProvider(String providerName) {
|
||||
IOauthProvider provider = providerMap.get(providerName);
|
||||
return provider;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.newyetai.security.social.wechat.constant;
|
||||
|
||||
/**
|
||||
* @author sr on 2021-01-13
|
||||
*/
|
||||
public interface WechatConstants {
|
||||
|
||||
/** 授权code获取token **/
|
||||
String TOKEN_URL_FORMAT =
|
||||
"https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=%s";
|
||||
|
||||
/** openId换取用户信息 **/
|
||||
String USER_URL_FORMAT =
|
||||
"https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=%s";
|
||||
|
||||
/** 调起微信授权地址 **/
|
||||
String AUTH_URL_FORMAT =
|
||||
"https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=%s&scope=%s&state=%s#wechat_redirect";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.newyetai.security.social.wechat.convert;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.RequestEntity;
|
||||
import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
import com.newyetai.security.social.wechat.constant.WechatConstants;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
|
||||
/**
|
||||
* code换token
|
||||
*
|
||||
* @author sr on 2021-01-12
|
||||
*/
|
||||
@Slf4j
|
||||
public class WeChatAuthorizationCodeGrantRequestEntityConverter
|
||||
implements Converter<OAuth2AuthorizationCodeGrantRequest, RequestEntity<?>> {
|
||||
|
||||
@Override
|
||||
public RequestEntity<?> convert(
|
||||
OAuth2AuthorizationCodeGrantRequest authorizationCodeGrantRequest) {
|
||||
HttpHeaders headers = getTokenRequestHeaders();
|
||||
URI uri = buildUri(authorizationCodeGrantRequest);
|
||||
return new RequestEntity<>(headers, HttpMethod.GET, uri);
|
||||
}
|
||||
|
||||
private HttpHeaders getTokenRequestHeaders() {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setAccept(Collections.singletonList(MediaType.TEXT_PLAIN));
|
||||
return headers;
|
||||
}
|
||||
|
||||
private URI buildUri(OAuth2AuthorizationCodeGrantRequest authorizationCodeGrantRequest) {
|
||||
ClientRegistration clientRegistration = authorizationCodeGrantRequest.getClientRegistration();
|
||||
String tokenUri = clientRegistration.getProviderDetails().getTokenUri();
|
||||
String appid = clientRegistration.getClientId();
|
||||
String secret = clientRegistration.getClientSecret();
|
||||
String code = authorizationCodeGrantRequest.getAuthorizationExchange()
|
||||
.getAuthorizationResponse().getCode();
|
||||
String grantType = authorizationCodeGrantRequest.getGrantType().getValue();
|
||||
|
||||
String uriString =
|
||||
String.format(WechatConstants.TOKEN_URL_FORMAT,
|
||||
appid, secret, code, grantType);
|
||||
return UriComponentsBuilder.fromUriString(uriString).build().toUri();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.newyetai.security.social.wechat.convert;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.RequestEntity;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
import com.newyetai.security.social.wechat.constant.WechatConstants;
|
||||
|
||||
public class WeChatUserRequestEntityConverter
|
||||
implements Converter<OAuth2UserRequest, RequestEntity<?>> {
|
||||
|
||||
@Override
|
||||
public RequestEntity<?> convert(OAuth2UserRequest userRequest) {
|
||||
HttpHeaders headers = getUserRequestHeaders();
|
||||
URI uri = buildUri(userRequest);
|
||||
return new RequestEntity<>(headers, HttpMethod.GET, uri);
|
||||
}
|
||||
|
||||
private HttpHeaders getUserRequestHeaders() {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setAccept(Collections.singletonList(MediaType.TEXT_PLAIN));
|
||||
return headers;
|
||||
}
|
||||
|
||||
private URI buildUri(OAuth2UserRequest userRequest) {
|
||||
ClientRegistration clientRegistration = userRequest.getClientRegistration();
|
||||
String uri = clientRegistration.getProviderDetails().getUserInfoEndpoint().getUri();
|
||||
String accessToken = userRequest.getAccessToken().getTokenValue();
|
||||
String openId = (String) userRequest.getAdditionalParameters().get("openid");
|
||||
|
||||
String userInfoUrl =
|
||||
String.format(WechatConstants.USER_URL_FORMAT,
|
||||
accessToken, openId, "zh_CN");
|
||||
return UriComponentsBuilder.fromUriString(userInfoUrl).build().toUri();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package com.newyetai.security.social.wechat.service;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest;
|
||||
import org.springframework.security.oauth2.core.OAuth2AccessToken;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.newyetai.common.util.JsonUtils;
|
||||
import com.newyetai.security.social.service.IOauthProvider;
|
||||
import com.newyetai.usercenter.constants.SecurityConstants;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Slf4j
|
||||
public class WeChatAccessTokenResponse {
|
||||
@JsonProperty("access_token")
|
||||
private String accessToken;
|
||||
@JsonProperty("expires_in")
|
||||
private Long expiresIn;
|
||||
@JsonProperty("refresh_token")
|
||||
private String refreshToken;
|
||||
private String openid;
|
||||
private String scope;
|
||||
|
||||
private WeChatAccessTokenResponse() {
|
||||
|
||||
}
|
||||
|
||||
public static WeChatAccessTokenResponse build(String json) {
|
||||
try {
|
||||
return JsonUtils.toObject(json, WeChatAccessTokenResponse.class);
|
||||
} catch (Exception e) {
|
||||
log.error("An error occurred while attempting to parse the WeiXin Access Token Response: "
|
||||
+ e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public OAuth2AccessTokenResponse toOAuth2AccessTokenResponse(
|
||||
OAuth2AuthorizationCodeGrantRequest authorizationCodeGrantRequest) {
|
||||
OAuth2AccessTokenResponse.Builder builder = OAuth2AccessTokenResponse.withToken(accessToken);
|
||||
builder.tokenType(OAuth2AccessToken.TokenType.BEARER);
|
||||
builder.expiresIn(expiresIn);
|
||||
builder.refreshToken(refreshToken);
|
||||
|
||||
String[] scopes = scope.split(",");
|
||||
Set<String> scopeSet = new HashSet<>();
|
||||
Collections.addAll(scopeSet, scopes);
|
||||
builder.scopes(scopeSet);
|
||||
|
||||
Map<String, Object> additionalParameters = new LinkedHashMap<>();
|
||||
additionalParameters.put("openid", openid);
|
||||
Map<String, Object> originParam = authorizationCodeGrantRequest.getAuthorizationExchange().getAuthorizationRequest()
|
||||
.getAdditionalParameters();
|
||||
additionalParameters.putAll(originParam);
|
||||
builder.additionalParameters(additionalParameters);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
package com.newyetai.security.social.wechat.service;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.collections4.MapUtils;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.http.RequestEntity;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest;
|
||||
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthorizationException;
|
||||
import org.springframework.security.oauth2.core.OAuth2Error;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResponseType;
|
||||
import org.springframework.security.oauth2.core.user.OAuth2User;
|
||||
import org.springframework.web.client.RestClientException;
|
||||
|
||||
import com.newyetai.common.util.JsonUtils;
|
||||
import com.newyetai.security.mapstruct.AuthDetailMapMapper;
|
||||
import com.newyetai.security.mapstruct.UserMapMapper;
|
||||
import com.newyetai.security.social.service.IOauthProvider;
|
||||
import com.newyetai.security.social.service.StandardAuthorizationCodeTokenResponseClient;
|
||||
import com.newyetai.security.social.wechat.constant.WechatConstants;
|
||||
import com.newyetai.security.social.wechat.convert.WeChatAuthorizationCodeGrantRequestEntityConverter;
|
||||
import com.newyetai.security.social.wechat.convert.WeChatUserRequestEntityConverter;
|
||||
import com.newyetai.security.util.SecurityUtils;
|
||||
import com.newyetai.usercenter.auth.constant.AuthTypeEnum;
|
||||
import com.newyetai.usercenter.auth.dto.AuthDetailLoginDTO;
|
||||
import com.newyetai.usercenter.auth.wechat.dto.WechatAuthUserInfoDTO;
|
||||
import com.newyetai.usercenter.constants.SecurityConstants;
|
||||
import com.newyetai.usercenter.user.login.dto.UserDetailDTO;
|
||||
import com.newyetai.usercenter.user.login.service.UserLoginService;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class WechatOauthLoginProvider implements IOauthProvider {
|
||||
|
||||
private Converter<OAuth2AuthorizationCodeGrantRequest, RequestEntity<?>> tokenConverter =
|
||||
new WeChatAuthorizationCodeGrantRequestEntityConverter();
|
||||
|
||||
private Converter<OAuth2UserRequest, RequestEntity<?>> userConverter =
|
||||
new WeChatUserRequestEntityConverter();
|
||||
|
||||
private UserLoginService userLoginService;
|
||||
|
||||
public WechatOauthLoginProvider(UserLoginService userLoginService) {
|
||||
this.userLoginService = userLoginService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return AuthTypeEnum.WECHAT.name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuth2AuthorizationRequest decorateRequest(HttpServletRequest request,
|
||||
OAuth2AuthorizationRequest authorizationRequest) {
|
||||
// 指定成功跳转地址
|
||||
String redirectUrl =
|
||||
SecurityUtils.dealRedirectUrl(request, authorizationRequest.getRedirectUri());
|
||||
|
||||
// 微信Authorization Request URL
|
||||
String authorizationRequestUri =
|
||||
String.format(WechatConstants.AUTH_URL_FORMAT,
|
||||
authorizationRequest.getClientId(),
|
||||
SecurityUtils.encodeURL(redirectUrl),
|
||||
OAuth2AuthorizationResponseType.CODE.getValue(), getScope(authorizationRequest),
|
||||
authorizationRequest.getState());
|
||||
|
||||
return OAuth2AuthorizationRequest.from(authorizationRequest)
|
||||
.authorizationRequestUri(authorizationRequestUri)
|
||||
.build();
|
||||
}
|
||||
|
||||
private static String getScope(OAuth2AuthorizationRequest authorizationRequest) {
|
||||
return authorizationRequest.getScopes().stream().findFirst().orElse("snsapi_userinfo");
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuth2AccessTokenResponse getTokenResponse(
|
||||
OAuth2AuthorizationCodeGrantRequest authorizationCodeGrantRequest) {
|
||||
|
||||
// 调用WeChatAuthorizationCodeGrantRequestEntityConverter获取request
|
||||
RequestEntity<?> request = this.tokenConverter.convert(authorizationCodeGrantRequest);
|
||||
|
||||
ResponseEntity<String> response;
|
||||
try {
|
||||
// 执行request
|
||||
response = StandardAuthorizationCodeTokenResponseClient.restOperations.exchange(request,
|
||||
String.class);
|
||||
} catch (RestClientException ex) {
|
||||
String description =
|
||||
"An error occurred while attempting to retrieve the OAuth 2.0 Access Token Response: ";
|
||||
log.error(description, ex);
|
||||
OAuth2Error oauth2Error =
|
||||
new OAuth2Error(
|
||||
StandardAuthorizationCodeTokenResponseClient.INVALID_TOKEN_RESPONSE_ERROR_CODE,
|
||||
description + ex.getMessage(), null);
|
||||
throw new OAuth2AuthorizationException(oauth2Error, ex);
|
||||
}
|
||||
|
||||
// 解析response
|
||||
OAuth2AccessTokenResponse tokenResponse =
|
||||
WeChatAccessTokenResponse.build(response.getBody()).toOAuth2AccessTokenResponse(authorizationCodeGrantRequest);
|
||||
|
||||
if (CollectionUtils.isEmpty(tokenResponse.getAccessToken().getScopes())) {
|
||||
tokenResponse = OAuth2AccessTokenResponse.withResponse(tokenResponse)
|
||||
.scopes(authorizationCodeGrantRequest.getClientRegistration().getScopes())
|
||||
.build();
|
||||
}
|
||||
|
||||
return tokenResponse;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Converter<OAuth2UserRequest, RequestEntity<?>> getUserConvert() {
|
||||
return userConverter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuth2User dealUser(OAuth2UserRequest userRequest, String userJsonStr) {
|
||||
WechatAuthUserInfoDTO wechatUserInfoDTO = null;
|
||||
try {
|
||||
// 编码转换
|
||||
userJsonStr = new String(userJsonStr.getBytes("ISO-8859-1"), "UTF-8");
|
||||
wechatUserInfoDTO = JsonUtils.toObject(userJsonStr, WechatAuthUserInfoDTO.class);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
log.error("An error occurred while attempting to encode userAttributes: " + e.getMessage());
|
||||
}
|
||||
AuthDetailLoginDTO authDetailLoginDTO = AuthDetailMapMapper.INSTANCE.toDto(wechatUserInfoDTO);
|
||||
Integer userType = MapUtils.getInteger(userRequest.getAdditionalParameters(),
|
||||
SecurityConstants.LOGIN_USER_TYPE_KEY);
|
||||
String registerCode = MapUtils.getString(userRequest.getAdditionalParameters(),
|
||||
SecurityConstants.LOGIN_REGISTER_CODE_KEY);
|
||||
String entrypoint = MapUtils.getString(userRequest.getAdditionalParameters(),
|
||||
SecurityConstants.LOGIN_ENTRYPOINT_KEY);
|
||||
authDetailLoginDTO
|
||||
.setUserType(userType);
|
||||
authDetailLoginDTO
|
||||
.setAuthClientId(Long.valueOf(userRequest.getClientRegistration().getRegistrationId()));
|
||||
authDetailLoginDTO.setAuthTypeCode(AuthTypeEnum.WECHAT.getCode());
|
||||
authDetailLoginDTO.setRegisterCode(registerCode);
|
||||
authDetailLoginDTO.setEntrypoint(entrypoint);
|
||||
UserDetailDTO userDetailDTO = userLoginService.findUserDetailDTO(authDetailLoginDTO);
|
||||
return UserMapMapper.INSTANCE.dtoToDto(userDetailDTO);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user