@@ -7,7 +7,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; | |||
public class SpringAuthorizationServerApplication { | |||
public static void main(String[] args) { | |||
SpringApplication.run(SpringAuthorizationServerApplication.class, args); | |||
System.out.println("TuoHeng-Oidc启动成功~"); | |||
System.out.println("TuoHeng-Oidc-Server启动成功~"); | |||
} | |||
} |
@@ -1,24 +1,36 @@ | |||
package com.tuoheng.config; | |||
import com.tuoheng.oauth2.authentication.OAuth2ResourceOwnerPasswordAuthenticationConverter; | |||
import com.tuoheng.handler.AccessDeniedHandler; | |||
import com.tuoheng.mapper.UserMapper; | |||
import com.tuoheng.model.dto.UserBaseInfoDto; | |||
//import com.tuoheng.oauth2.authentication.OAuth2ResourceOwnerPasswordAuthenticationProvider; | |||
import com.tuoheng.oauth2.authentication.OAuth2ResourceOwnerPasswordAuthenticationProvider; | |||
import com.tuoheng.service.impl.OidcUserInfoServiceImpl; | |||
import lombok.RequiredArgsConstructor; | |||
import org.springframework.beans.factory.annotation.Autowired; | |||
import org.springframework.context.annotation.Bean; | |||
import org.springframework.context.annotation.Configuration; | |||
import org.springframework.core.annotation.Order; | |||
import org.springframework.security.authentication.AuthenticationManager; | |||
import org.springframework.security.config.Customizer; | |||
import org.springframework.security.config.annotation.web.builders.HttpSecurity; | |||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; | |||
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer; | |||
import org.springframework.security.config.annotation.web.configurers.oauth2.server.authorization.OAuth2AuthorizationServerConfigurer; | |||
import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer; | |||
import org.springframework.security.core.userdetails.UserDetailsService; | |||
import org.springframework.security.oauth2.core.OAuth2Token; | |||
import org.springframework.security.oauth2.core.oidc.OidcUserInfo; | |||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService; | |||
import org.springframework.security.oauth2.server.authorization.config.ProviderSettings; | |||
import org.springframework.security.oauth2.server.authorization.oidc.authentication.OidcUserInfoAuthenticationContext; | |||
import org.springframework.security.oauth2.server.authorization.oidc.authentication.OidcUserInfoAuthenticationToken; | |||
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator; | |||
import org.springframework.security.oauth2.server.authorization.web.authentication.DelegatingAuthenticationConverter; | |||
import org.springframework.security.oauth2.server.authorization.web.authentication.OAuth2AuthorizationCodeAuthenticationConverter; | |||
import org.springframework.security.oauth2.server.authorization.web.authentication.OAuth2ClientCredentialsAuthenticationConverter; | |||
import org.springframework.security.oauth2.server.authorization.web.authentication.OAuth2RefreshTokenAuthenticationConverter; | |||
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; | |||
import org.springframework.security.provisioning.JdbcUserDetailsManager; | |||
import org.springframework.security.web.SecurityFilterChain; | |||
@@ -27,6 +39,7 @@ import org.springframework.security.web.authentication.UsernamePasswordAuthentic | |||
import org.springframework.security.web.util.matcher.RequestMatcher; | |||
import javax.sql.DataSource; | |||
import java.util.Arrays; | |||
import java.util.function.Function; | |||
/** | |||
@@ -51,6 +64,14 @@ public class SecurityConfig { | |||
OAuth2AuthorizationServerConfigurer<HttpSecurity> authorizationServerConfigurer = | |||
new OAuth2AuthorizationServerConfigurer<>(); | |||
http.apply(authorizationServerConfigurer | |||
.tokenEndpoint((tokenEndpoint) -> tokenEndpoint.accessTokenRequestConverter(new DelegatingAuthenticationConverter( | |||
Arrays.asList( | |||
new OAuth2AuthorizationCodeAuthenticationConverter(), | |||
new OAuth2RefreshTokenAuthenticationConverter(), | |||
new OAuth2ClientCredentialsAuthenticationConverter(), | |||
new OAuth2ResourceOwnerPasswordAuthenticationConverter()))))); | |||
OidcUserInfoServiceImpl oidcUserInfoService = new OidcUserInfoServiceImpl(); | |||
//自定义用户映射器 | |||
Function<OidcUserInfoAuthenticationContext, OidcUserInfo> userInfoMapper = (context) -> { | |||
@@ -65,7 +86,7 @@ public class SecurityConfig { | |||
RequestMatcher endpointsMatcher = authorizationServerConfigurer.getEndpointsMatcher(); | |||
return http.requestMatcher(endpointsMatcher) | |||
http.requestMatcher(endpointsMatcher) | |||
.authorizeRequests((authorizeRequests) -> { | |||
((ExpressionUrlAuthorizationConfigurer.AuthorizedUrl) authorizeRequests.anyRequest()).authenticated(); | |||
}).csrf((csrf) -> { | |||
@@ -77,9 +98,10 @@ public class SecurityConfig { | |||
.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/toLogin")) | |||
.accessDeniedHandler(new AccessDeniedHandler())) | |||
//.authenticationEntryPoint(new AuthenticationEntryPoint())) | |||
.apply(authorizationServerConfigurer) | |||
.and() | |||
.build(); | |||
.apply(authorizationServerConfigurer); | |||
SecurityFilterChain securityFilterChain = http.build(); | |||
addCustomOAuth2ResourceOwnerPasswordAuthenticationProvider(http); | |||
return securityFilterChain; | |||
} | |||
@Bean | |||
@@ -90,7 +112,7 @@ public class SecurityConfig { | |||
http.csrf().disable() | |||
.authorizeHttpRequests((authorize) -> authorize | |||
.antMatchers("/toLogin", "/getHealth", "/static/**", "/vercode").permitAll() | |||
.antMatchers("/user/create").permitAll() | |||
.antMatchers("/user/create","/user/getInfo").permitAll() | |||
.anyRequest().authenticated() | |||
) | |||
// Form login handles the redirect to the login page from the | |||
@@ -101,7 +123,8 @@ public class SecurityConfig { | |||
.loginProcessingUrl("/login") | |||
) | |||
.logout() | |||
.logoutSuccessUrl("/toLogout"); | |||
.logoutSuccessUrl("/toLogout") | |||
.and(); | |||
return http.build(); | |||
} | |||
@@ -129,4 +152,19 @@ public class SecurityConfig { | |||
return new BCryptPasswordEncoder(); | |||
}*/ | |||
@SuppressWarnings("unchecked") | |||
private void addCustomOAuth2ResourceOwnerPasswordAuthenticationProvider(HttpSecurity http) { | |||
AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManager.class); | |||
OAuth2AuthorizationService authorizationService = http.getSharedObject(OAuth2AuthorizationService.class); | |||
OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator = http.getSharedObject(OAuth2TokenGenerator.class); | |||
OAuth2ResourceOwnerPasswordAuthenticationProvider resourceOwnerPasswordAuthenticationProvider = | |||
new OAuth2ResourceOwnerPasswordAuthenticationProvider(authenticationManager, authorizationService, tokenGenerator); | |||
// This will add new authentication provider in the list of existing authentication providers. | |||
http.authenticationProvider(resourceOwnerPasswordAuthenticationProvider); | |||
} | |||
} |
@@ -1,6 +1,7 @@ | |||
package com.tuoheng.controller; | |||
import com.tuoheng.model.param.CreateUserDto; | |||
import com.tuoheng.model.param.GetUserInfoDto; | |||
import com.tuoheng.service.UserSevice; | |||
import com.tuoheng.until.JsonResult; | |||
import org.springframework.beans.factory.annotation.Autowired; | |||
@@ -24,4 +25,14 @@ public class UserController { | |||
return userSevice.createUser(createUserDto); | |||
} | |||
/** | |||
* 小程序端获取用户信息端点 | |||
* @param getUserInfoDto | |||
* @return | |||
*/ | |||
@PostMapping("/getInfo") | |||
public JsonResult getUserInfo(@RequestBody GetUserInfoDto getUserInfoDto){ | |||
return userSevice.getUserInfo(getUserInfoDto); | |||
} | |||
} |
@@ -16,4 +16,7 @@ public interface UserMapper { | |||
UserBaseInfoDto getUserBaseInfo(String username); | |||
UserBaseInfoDto getMpUserInfo(String username); | |||
} |
@@ -0,0 +1,23 @@ | |||
package com.tuoheng.model.param; | |||
import lombok.Data; | |||
import javax.validation.constraints.NotEmpty; | |||
import javax.validation.constraints.NotNull; | |||
import java.util.List; | |||
/** | |||
* @author chenjiandong | |||
* @description: TODO | |||
* @date 2022/10/8 11:30 | |||
*/ | |||
@Data | |||
public class GetUserInfoDto { | |||
@NotEmpty(message = "username can not be empty!") | |||
private String username; | |||
@NotEmpty(message = "token can not be empty!") | |||
private String token; | |||
} |
@@ -0,0 +1,69 @@ | |||
package com.tuoheng.oauth2.authentication; | |||
import java.util.Collections; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
import javax.servlet.http.HttpServletRequest; | |||
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.endpoint.OAuth2ParameterNames; | |||
import org.springframework.security.oauth2.core.endpoint.PkceParameterNames; | |||
import org.springframework.util.LinkedMultiValueMap; | |||
import org.springframework.util.MultiValueMap; | |||
/** | |||
* Utility methods for the OAuth 2.0 Protocol Endpoints. | |||
* | |||
* @author Joe Grandja | |||
* @since 0.1.2 | |||
*/ | |||
final class OAuth2EndpointUtils { | |||
static final String ACCESS_TOKEN_REQUEST_ERROR_URI = "https://datatracker.ietf.org/doc/html/rfc6749#section-5.2"; | |||
private OAuth2EndpointUtils() { | |||
} | |||
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) -> { | |||
if (values.length > 0) { | |||
for (String value : values) { | |||
parameters.add(key, value); | |||
} | |||
} | |||
}); | |||
return parameters; | |||
} | |||
static Map<String, Object> getParametersIfMatchesAuthorizationCodeGrantRequest(HttpServletRequest request, String... exclusions) { | |||
if (!matchesAuthorizationCodeGrantRequest(request)) { | |||
return Collections.emptyMap(); | |||
} | |||
Map<String, Object> parameters = new HashMap<>(getParameters(request).toSingleValueMap()); | |||
for (String exclusion : exclusions) { | |||
parameters.remove(exclusion); | |||
} | |||
return parameters; | |||
} | |||
static boolean matchesAuthorizationCodeGrantRequest(HttpServletRequest request) { | |||
return AuthorizationGrantType.AUTHORIZATION_CODE.getValue().equals( | |||
request.getParameter(OAuth2ParameterNames.GRANT_TYPE)) && | |||
request.getParameter(OAuth2ParameterNames.CODE) != null; | |||
} | |||
static boolean matchesPkceTokenRequest(HttpServletRequest request) { | |||
return matchesAuthorizationCodeGrantRequest(request) && | |||
request.getParameter(PkceParameterNames.CODE_VERIFIER) != null; | |||
} | |||
static void throwError(String errorCode, String parameterName, String errorUri) { | |||
OAuth2Error error = new OAuth2Error(errorCode, "OAuth 2.0 Parameter: " + parameterName, errorUri); | |||
throw new OAuth2AuthenticationException(error); | |||
} | |||
} |
@@ -0,0 +1,89 @@ | |||
package com.tuoheng.oauth2.authentication; | |||
import java.util.Arrays; | |||
import java.util.HashSet; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import java.util.stream.Collectors; | |||
import javax.servlet.http.HttpServletRequest; | |||
import org.springframework.lang.Nullable; | |||
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.OAuth2ErrorCodes; | |||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames; | |||
import org.springframework.security.web.authentication.AuthenticationConverter; | |||
import org.springframework.util.MultiValueMap; | |||
import org.springframework.util.StringUtils; | |||
public class OAuth2ResourceOwnerPasswordAuthenticationConverter implements AuthenticationConverter { | |||
@Nullable | |||
@Override | |||
public Authentication convert(HttpServletRequest request) { | |||
// grant_type (REQUIRED) | |||
String grantType = request.getParameter(OAuth2ParameterNames.GRANT_TYPE); | |||
if (!AuthorizationGrantType.PASSWORD.getValue().equals(grantType)) { | |||
return null; | |||
} | |||
MultiValueMap<String, String> parameters = OAuth2EndpointUtils.getParameters(request); | |||
// scope (OPTIONAL) | |||
String scope = parameters.getFirst(OAuth2ParameterNames.SCOPE); | |||
if (StringUtils.hasText(scope) && | |||
parameters.get(OAuth2ParameterNames.SCOPE).size() != 1) { | |||
OAuth2EndpointUtils.throwError( | |||
OAuth2ErrorCodes.INVALID_REQUEST, | |||
OAuth2ParameterNames.SCOPE, | |||
OAuth2EndpointUtils.ACCESS_TOKEN_REQUEST_ERROR_URI); | |||
} | |||
Set<String> requestedScopes = null; | |||
if (StringUtils.hasText(scope)) { | |||
requestedScopes = new HashSet<>( | |||
Arrays.asList(StringUtils.delimitedListToStringArray(scope, " "))); | |||
} | |||
// username (REQUIRED) | |||
String username = parameters.getFirst(OAuth2ParameterNames.USERNAME); | |||
if (!StringUtils.hasText(username) || parameters.get(OAuth2ParameterNames.USERNAME).size() != 1) { | |||
OAuth2EndpointUtils.throwError( | |||
OAuth2ErrorCodes.INVALID_REQUEST, | |||
OAuth2ParameterNames.USERNAME, | |||
OAuth2EndpointUtils.ACCESS_TOKEN_REQUEST_ERROR_URI); | |||
} | |||
// password (REQUIRED) | |||
String password = parameters.getFirst(OAuth2ParameterNames.PASSWORD); | |||
if (!StringUtils.hasText(password) || parameters.get(OAuth2ParameterNames.PASSWORD).size() != 1) { | |||
OAuth2EndpointUtils.throwError( | |||
OAuth2ErrorCodes.INVALID_REQUEST, | |||
OAuth2ParameterNames.PASSWORD, | |||
OAuth2EndpointUtils.ACCESS_TOKEN_REQUEST_ERROR_URI); | |||
} | |||
Authentication clientPrincipal = SecurityContextHolder.getContext().getAuthentication(); | |||
if (clientPrincipal == null) { | |||
OAuth2EndpointUtils.throwError( | |||
OAuth2ErrorCodes.INVALID_REQUEST, | |||
OAuth2ErrorCodes.INVALID_CLIENT, | |||
OAuth2EndpointUtils.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))); | |||
return new OAuth2ResourceOwnerPasswordAuthenticationToken( | |||
AuthorizationGrantType.PASSWORD, clientPrincipal, requestedScopes, additionalParameters); | |||
} | |||
} |
@@ -0,0 +1,186 @@ | |||
package com.tuoheng.oauth2.authentication; | |||
import org.apache.logging.log4j.LogManager; | |||
import org.apache.logging.log4j.Logger; | |||
import org.springframework.security.authentication.AuthenticationManager; | |||
import org.springframework.security.authentication.AuthenticationProvider; | |||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; | |||
import org.springframework.security.core.Authentication; | |||
import org.springframework.security.core.AuthenticationException; | |||
import org.springframework.security.oauth2.core.*; | |||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames; | |||
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization; | |||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService; | |||
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.ProviderContextHolder; | |||
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.Assert; | |||
import org.springframework.util.CollectionUtils; | |||
import java.security.Principal; | |||
import java.util.Collections; | |||
import java.util.LinkedHashSet; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import java.util.stream.Collectors; | |||
public class OAuth2ResourceOwnerPasswordAuthenticationProvider implements AuthenticationProvider { | |||
private static final Logger LOGGER = LogManager.getLogger(); | |||
private static final String ERROR_URI = "https://datatracker.ietf.org/doc/html/rfc6749#section-5.2"; | |||
private final AuthenticationManager authenticationManager; | |||
private final OAuth2AuthorizationService authorizationService; | |||
private final OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator; | |||
/** | |||
* Constructs an {@code OAuth2ResourceOwnerPasswordAuthenticationProviderNew} using the provided parameters. | |||
* | |||
* @param authenticationManager the authentication manager | |||
* @param authorizationService the authorization service | |||
* @param tokenGenerator the token generator | |||
* @since 0.2.3 | |||
*/ | |||
public OAuth2ResourceOwnerPasswordAuthenticationProvider(AuthenticationManager authenticationManager, | |||
OAuth2AuthorizationService authorizationService, OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator) { | |||
Assert.notNull(authorizationService, "authorizationService cannot be null"); | |||
Assert.notNull(tokenGenerator, "tokenGenerator cannot be null"); | |||
this.authenticationManager = authenticationManager; | |||
this.authorizationService = authorizationService; | |||
this.tokenGenerator = tokenGenerator; | |||
} | |||
@Override | |||
public Authentication authenticate(Authentication authentication) throws AuthenticationException { | |||
OAuth2ResourceOwnerPasswordAuthenticationToken resouceOwnerPasswordAuthentication = (OAuth2ResourceOwnerPasswordAuthenticationToken) authentication; | |||
OAuth2ClientAuthenticationToken clientPrincipal = getAuthenticatedClientElseThrowInvalidClient(resouceOwnerPasswordAuthentication); | |||
RegisteredClient registeredClient = clientPrincipal.getRegisteredClient(); | |||
if (!registeredClient.getAuthorizationGrantTypes().contains(AuthorizationGrantType.PASSWORD)) { | |||
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.UNAUTHORIZED_CLIENT); | |||
} | |||
Authentication usernamePasswordAuthentication = getUsernamePasswordAuthentication(resouceOwnerPasswordAuthentication); | |||
Set<String> authorizedScopes = registeredClient.getScopes(); // Default to configured scopes | |||
Set<String> requestedScopes = resouceOwnerPasswordAuthentication.getScopes(); | |||
if (!CollectionUtils.isEmpty(requestedScopes)) { | |||
Set<String> unauthorizedScopes = requestedScopes.stream() | |||
.filter(requestedScope -> !registeredClient.getScopes().contains(requestedScope)) | |||
.collect(Collectors.toSet()); | |||
if (!CollectionUtils.isEmpty(unauthorizedScopes)) { | |||
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_SCOPE); | |||
} | |||
authorizedScopes = new LinkedHashSet<>(requestedScopes); | |||
} | |||
// @formatter:off | |||
DefaultOAuth2TokenContext.Builder tokenContextBuilder = DefaultOAuth2TokenContext.builder() | |||
.registeredClient(registeredClient) | |||
.principal(usernamePasswordAuthentication) | |||
.providerContext(ProviderContextHolder.getProviderContext()) | |||
.authorizedScopes(authorizedScopes) | |||
.authorizationGrantType(AuthorizationGrantType.PASSWORD) | |||
.authorizationGrant(resouceOwnerPasswordAuthentication); | |||
// @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()); | |||
// ----- 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; | |||
} | |||
// @formatter:off | |||
OAuth2Authorization.Builder authorizationBuilder = OAuth2Authorization.withRegisteredClient(registeredClient) | |||
.principalName(usernamePasswordAuthentication.getName()) | |||
.authorizationGrantType(AuthorizationGrantType.PASSWORD) | |||
.attribute(OAuth2Authorization.AUTHORIZED_SCOPE_ATTRIBUTE_NAME, authorizedScopes) | |||
.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); | |||
} | |||
OAuth2Authorization authorization = authorizationBuilder.build(); | |||
this.authorizationService.save(authorization); | |||
LOGGER.debug("OAuth2Authorization saved successfully"); | |||
Map<String, Object> additionalParameters = Collections.emptyMap(); | |||
LOGGER.debug("returning OAuth2AccessTokenAuthenticationToken"); | |||
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, accessToken, refreshToken, additionalParameters); | |||
} | |||
@Override | |||
public boolean supports(Class<?> authentication) { | |||
return OAuth2ResourceOwnerPasswordAuthenticationToken.class.isAssignableFrom(authentication); | |||
} | |||
private Authentication getUsernamePasswordAuthentication(OAuth2ResourceOwnerPasswordAuthenticationToken resouceOwnerPasswordAuthentication) { | |||
Map<String, Object> additionalParameters = resouceOwnerPasswordAuthentication.getAdditionalParameters(); | |||
String username = (String) additionalParameters.get(OAuth2ParameterNames.USERNAME); | |||
String password = (String) additionalParameters.get(OAuth2ParameterNames.PASSWORD); | |||
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(username, password); | |||
LOGGER.debug("got usernamePasswordAuthenticationToken=" + usernamePasswordAuthenticationToken); | |||
Authentication usernamePasswordAuthentication = authenticationManager.authenticate(usernamePasswordAuthenticationToken); | |||
return usernamePasswordAuthentication; | |||
} | |||
private 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); | |||
} | |||
} |
@@ -0,0 +1,75 @@ | |||
package com.tuoheng.oauth2.authentication; | |||
import org.springframework.lang.Nullable; | |||
import org.springframework.security.authentication.AbstractAuthenticationToken; | |||
import org.springframework.security.core.Authentication; | |||
import org.springframework.security.oauth2.core.AuthorizationGrantType; | |||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationGrantAuthenticationToken; | |||
import org.springframework.util.Assert; | |||
import java.util.*; | |||
public class OAuth2ResourceOwnerPasswordAuthenticationToken extends AbstractAuthenticationToken { | |||
private static final long serialVersionUID = -6067207202119450764L; | |||
private final AuthorizationGrantType authorizationGrantType; | |||
private final Authentication clientPrincipal; | |||
private final Set<String> scopes; | |||
private final Map<String, Object> additionalParameters; | |||
/** | |||
* Constructs an {@code OAuth2ClientCredentialsAuthenticationToken} using the provided parameters. | |||
* | |||
* @param clientPrincipal the authenticated client principal | |||
*/ | |||
public OAuth2ResourceOwnerPasswordAuthenticationToken(AuthorizationGrantType authorizationGrantType, | |||
Authentication clientPrincipal, @Nullable Set<String> scopes, @Nullable Map<String, Object> additionalParameters) { | |||
super(Collections.emptyList()); | |||
Assert.notNull(authorizationGrantType, "authorizationGrantType cannot be null"); | |||
Assert.notNull(clientPrincipal, "clientPrincipal cannot be null"); | |||
this.authorizationGrantType = authorizationGrantType; | |||
this.clientPrincipal = clientPrincipal; | |||
this.scopes = Collections.unmodifiableSet(scopes != null ? new HashSet<>(scopes) : Collections.emptySet()); | |||
this.additionalParameters = Collections.unmodifiableMap(additionalParameters != null ? new HashMap<>(additionalParameters) : Collections.emptyMap()); | |||
} | |||
/** | |||
* Returns the authorization grant type. | |||
* | |||
* @return the authorization grant type | |||
*/ | |||
public AuthorizationGrantType getGrantType() { | |||
return this.authorizationGrantType; | |||
} | |||
@Override | |||
public Object getPrincipal() { | |||
return this.clientPrincipal; | |||
} | |||
@Override | |||
public Object getCredentials() { | |||
return ""; | |||
} | |||
/** | |||
* Returns the requested scope(s). | |||
* | |||
* @return the requested scope(s), or an empty {@code Set} if not available | |||
*/ | |||
public Set<String> getScopes() { | |||
return this.scopes; | |||
} | |||
/** | |||
* Returns the additional parameters. | |||
* | |||
* @return the additional parameters | |||
*/ | |||
public Map<String, Object> getAdditionalParameters() { | |||
return this.additionalParameters; | |||
} | |||
} |
@@ -1,6 +1,7 @@ | |||
package com.tuoheng.service; | |||
import com.tuoheng.model.param.CreateUserDto; | |||
import com.tuoheng.model.param.GetUserInfoDto; | |||
import com.tuoheng.until.JsonResult; | |||
/** | |||
* @author chenjiandong | |||
@@ -11,4 +12,6 @@ public interface UserSevice { | |||
JsonResult createUser(CreateUserDto createUserDto); | |||
JsonResult getUserInfo(GetUserInfoDto getUserInfoDto); | |||
} |
@@ -2,7 +2,9 @@ package com.tuoheng.service.impl; | |||
import com.tuoheng.mapper.AuthoritiesMapper; | |||
import com.tuoheng.mapper.UserMapper; | |||
import com.tuoheng.model.dto.UserBaseInfoDto; | |||
import com.tuoheng.model.param.CreateUserDto; | |||
import com.tuoheng.model.param.GetUserInfoDto; | |||
import com.tuoheng.model.po.AuthoritiesPo; | |||
import com.tuoheng.model.po.UserPo; | |||
import com.tuoheng.service.UserSevice; | |||
@@ -12,6 +14,9 @@ import org.springframework.beans.factory.annotation.Autowired; | |||
import org.springframework.security.core.userdetails.User; | |||
import org.springframework.security.core.userdetails.UserDetails; | |||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; | |||
import org.springframework.security.oauth2.core.oidc.OidcUserInfo; | |||
import org.springframework.security.oauth2.server.authorization.oidc.authentication.OidcUserInfoAuthenticationToken; | |||
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; | |||
import org.springframework.security.provisioning.UserDetailsManager; | |||
import org.springframework.stereotype.Service; | |||
import org.springframework.transaction.annotation.Transactional; | |||
@@ -54,4 +59,11 @@ public class UserServiceImpl implements UserSevice { | |||
return JsonResult.success(userPo.getId()); | |||
} | |||
@Override | |||
public JsonResult getUserInfo(GetUserInfoDto getUserInfoDto){ | |||
UserBaseInfoDto userBaseInfoDto = userMapper.getMpUserInfo(getUserInfoDto.getUsername()); | |||
return JsonResult.success(userBaseInfoDto); | |||
} | |||
} |
@@ -24,4 +24,11 @@ | |||
where a.username = #{username} | |||
</select> | |||
<select id="getMpUserInfo" resultMap="UserBaseInfoMap"> | |||
select a.id as userId, a.username as userName, b.authority | |||
from users a | |||
inner join authorities b on a.id = b.user_id | |||
where a.username = #{username} | |||
</select> | |||
</mapper> |