当前位置: 首页 > news >正文

洛阳高端网站建设/上海外贸seo

洛阳高端网站建设,上海外贸seo,百数低代码开发平台,国外美国服务器写在前面 Spring官方已经停止对Spring Security Oauth2的维护,项目和相关文档也被移除 Spring Authorization Server是官方新推出的OAuth2.1和OpenID Connect1.0的实现 两个主要的版本,0.4.x:jdk8。1.x: jdk17 这里用的版本是0.4.1 OAuth2…

写在前面

Spring官方已经停止对Spring Security Oauth2的维护,项目和相关文档也被移除

Spring Authorization Server是官方新推出的OAuth2.1和OpenID Connect1.0的实现
两个主要的版本,0.4.x:jdk8。1.x: jdk17
这里用的版本是0.4.1

OAuth2.0已经不在推荐使用密码模式,OAuth2.1已经废除密码模式,这是为了安全考虑。

比如:我开发了一个网站,可以使用微信登录,我要求你提供用户名和密码,然后我拿到用户名和密码之后,去模拟你登录微信然后获取用户信息,也就是说我拿到了你的密码,然后我就能在你不知情的情况下做某些敏感操作,比如拉黑你的所有好友。当然:微信肯定有自己的验证,这些敏感的操作会被屏蔽。这里我只是举了一个例子。

通常且正确的模式是使用授权码模式。这里不多解释了,你可以简单理解为,在我这边登录,我返回token给你,然后你再用这个token去获取用户信息。当然,授权码模式复杂一点。

但是有个需求,第三方使用接入我平台的认证的时候,我允许提供用户名密码给第三方,然后第三方使用密码模式在我这边登录并拿到token,第三方拿到用户名密码后,允许第三方保存这个用户名和密码。这种方式是不是很扯,虽然不安全,但还是有这样的需求,需求大于一切。

Spring Security Oauth2里面没有密码模式的实现,所以我们需要自己写。

实现

代码结构如下:很简单
在这里插入图片描述

  • 添加依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>com.demo.security</groupId><artifactId>demo-security</artifactId><version>1.0.0-SNAPSHOT</version></parent><artifactId>demo-pwd-support</artifactId><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-oauth2-authorization-server</artifactId></dependency></dependencies></project>

在这里插入图片描述
这里重写了登录页面,是因为默认的登录页面会从国外加载某个资源(css),浏览器访问不了,所以很卡,这里就重写了一下登录页面,非常简单。

  • OpenAuthEndpointUtils
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;import javax.servlet.http.HttpServletRequest;
import java.util.Map;public class OpenAuthEndpointUtils {static final String ACCESS_TOKEN_REQUEST_ERROR_URI = "https://datatracker.ietf.org/doc/html/rfc6749#section-5.2";private OpenAuthEndpointUtils() {}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 boolean matchesPkceTokenRequest(HttpServletRequest request) {return AuthorizationGrantType.AUTHORIZATION_CODE.getValue().equals(request.getParameter(OAuth2ParameterNames.GRANT_TYPE)) &&request.getParameter(OAuth2ParameterNames.CODE) != null &&request.getParameter(PkceParameterNames.CODE_VERIFIER) != null;}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);}}
  • OpenAuthPasswordAuthenticationConverter
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;import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;public class OpenAuthPasswordAuthenticationConverter implements AuthenticationConverter {@Overridepublic 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 = OpenAuthEndpointUtils.getParameters(request);// scope (OPTIONAL)String scope = parameters.getFirst(OAuth2ParameterNames.SCOPE);if (StringUtils.hasText(scope) &&parameters.get(OAuth2ParameterNames.SCOPE).size() != 1) {OpenAuthEndpointUtils.throwError(OAuth2ErrorCodes.INVALID_REQUEST,OAuth2ParameterNames.SCOPE,OpenAuthEndpointUtils.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) {OpenAuthEndpointUtils.throwError(OAuth2ErrorCodes.INVALID_REQUEST,OAuth2ParameterNames.USERNAME,OpenAuthEndpointUtils.ACCESS_TOKEN_REQUEST_ERROR_URI);}// password (REQUIRED)String password = parameters.getFirst(OAuth2ParameterNames.PASSWORD);if (!StringUtils.hasText(password) || parameters.get(OAuth2ParameterNames.PASSWORD).size() != 1) {OpenAuthEndpointUtils.throwError(OAuth2ErrorCodes.INVALID_REQUEST,OAuth2ParameterNames.PASSWORD,OpenAuthEndpointUtils.ACCESS_TOKEN_REQUEST_ERROR_URI);}Authentication clientPrincipal = SecurityContextHolder.getContext().getAuthentication();if (clientPrincipal == null) {OpenAuthEndpointUtils.throwError(OAuth2ErrorCodes.INVALID_REQUEST,OAuth2ErrorCodes.INVALID_CLIENT,OpenAuthEndpointUtils.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 OpenAuthPasswordAuthenticationToken(AuthorizationGrantType.PASSWORD, clientPrincipal, requestedScopes, additionalParameters);}}
  • OpenAuthPasswordAuthenticationProvider
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.core.oidc.OidcIdToken;
import org.springframework.security.oauth2.core.oidc.OidcScopes;
import org.springframework.security.oauth2.core.oidc.endpoint.OidcParameterNames;
import org.springframework.security.oauth2.jwt.Jwt;
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.Assert;
import org.springframework.util.CollectionUtils;import java.security.Principal;
import java.util.*;
import java.util.stream.Collectors;public class OpenAuthPasswordAuthenticationProvider 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 static final OAuth2TokenType ID_TOKEN_TOKEN_TYPE = new OAuth2TokenType(OidcParameterNames.ID_TOKEN);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 OpenAuthPasswordAuthenticationProvider(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;}@Overridepublic Authentication authenticate(Authentication authentication) throws AuthenticationException {OpenAuthPasswordAuthenticationToken resouceOwnerPasswordAuthentication = (OpenAuthPasswordAuthenticationToken) authentication;OAuth2ClientAuthenticationToken clientPrincipal = getAuthenticatedClientElseThrowInvalidClient(resouceOwnerPasswordAuthentication);RegisteredClient registeredClient = clientPrincipal.getRegisteredClient();if (LOGGER.isTraceEnabled()) {LOGGER.trace("Retrieved registered client");}if (!registeredClient.getAuthorizationGrantTypes().contains(AuthorizationGrantType.PASSWORD)) {throw new OAuth2AuthenticationException(OAuth2ErrorCodes.UNAUTHORIZED_CLIENT);}Authentication usernamePasswordAuthentication = getUsernamePasswordAuthentication(resouceOwnerPasswordAuthentication);Set<String> authorizedScopes = registeredClient.getScopes();		// Default to configured scopesSet<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);}if (LOGGER.isTraceEnabled()) {LOGGER.trace("Validated token request parameters");}// @formatter:offDefaultOAuth2TokenContext.Builder tokenContextBuilder = DefaultOAuth2TokenContext.builder().registeredClient(registeredClient).principal(usernamePasswordAuthentication).authorizationServerContext(AuthorizationServerContextHolder.getContext()).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);}if (LOGGER.isTraceEnabled()) {LOGGER.trace("Generated access token");}OAuth2AccessToken accessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,generatedAccessToken.getTokenValue(), generatedAccessToken.getIssuedAt(),generatedAccessToken.getExpiresAt(), tokenContext.getAuthorizedScopes());// @formatter:offOAuth2Authorization.Builder authorizationBuilder = OAuth2Authorization.withRegisteredClient(registeredClient).principalName(usernamePasswordAuthentication.getName()).authorizationGrantType(AuthorizationGrantType.PASSWORD).authorizedScopes(authorizedScopes).attribute(Principal.class.getName(), usernamePasswordAuthentication);// @formatter:onif (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);}if (LOGGER.isTraceEnabled()) {LOGGER.trace("Generated refresh token");}refreshToken = (OAuth2RefreshToken) generatedRefreshToken;authorizationBuilder.refreshToken(refreshToken);}// ----- ID token -----OidcIdToken idToken;if (requestedScopes.contains(OidcScopes.OPENID)) {// @formatter:offtokenContext = tokenContextBuilder.tokenType(ID_TOKEN_TOKEN_TYPE).authorization(authorizationBuilder.build())	// ID token customizer may need access to the access token and/or refresh token.build();// @formatter:onOAuth2Token generatedIdToken = this.tokenGenerator.generate(tokenContext);if (!(generatedIdToken instanceof Jwt)) {OAuth2Error error = new OAuth2Error(OAuth2ErrorCodes.SERVER_ERROR,"The token generator failed to generate the ID token.", ERROR_URI);throw new OAuth2AuthenticationException(error);}if (LOGGER.isTraceEnabled()) {LOGGER.trace("Generated id token");}idToken = new OidcIdToken(generatedIdToken.getTokenValue(), generatedIdToken.getIssuedAt(),generatedIdToken.getExpiresAt(), ((Jwt) generatedIdToken).getClaims());authorizationBuilder.token(idToken, (metadata) ->metadata.put(OAuth2Authorization.Token.CLAIMS_METADATA_NAME, idToken.getClaims()));} else {idToken = null;}OAuth2Authorization authorization = authorizationBuilder.build();this.authorizationService.save(authorization);if (LOGGER.isTraceEnabled()) {LOGGER.trace("Saved authorization");}Map<String, Object> additionalParameters = Collections.emptyMap();if (idToken != null) {additionalParameters = new HashMap<>();additionalParameters.put(OidcParameterNames.ID_TOKEN, idToken.getTokenValue());}if (LOGGER.isTraceEnabled()) {LOGGER.trace("Authenticated token request");}return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, accessToken, refreshToken, additionalParameters);}@Overridepublic boolean supports(Class<?> authentication) {boolean supports = OpenAuthPasswordAuthenticationToken.class.isAssignableFrom(authentication);LOGGER.debug("supports authentication=" + authentication + " returning " + supports);return supports;}private Authentication getUsernamePasswordAuthentication(OpenAuthPasswordAuthenticationToken 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);}}
  • OpenAuthPasswordAuthenticationToken
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.util.Assert;import java.util.*;public class OpenAuthPasswordAuthenticationToken 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 OpenAuthPasswordAuthenticationToken(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;}@Overridepublic Object getPrincipal() {return this.clientPrincipal;}@Overridepublic 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;}}
  • SecurityConfig
import com.demo.pwd.security.OpenAuthPasswordAuthenticationConverter;
import com.demo.pwd.security.OpenAuthPasswordAuthenticationProvider;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.proc.SecurityContext;
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.oauth2.server.resource.OAuth2ResourceServerConfigurer;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
import org.springframework.security.oauth2.core.OAuth2Token;
import org.springframework.security.oauth2.core.oidc.OidcScopes;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
import org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
import org.springframework.security.oauth2.server.authorization.settings.TokenSettings;
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.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.time.Duration;
import java.util.Arrays;
import java.util.UUID;/*** TODO description** @author qiudw* @date 6/7/2023*/
@Configuration
@EnableWebSecurity(debug = true)
public class SecurityConfig {private static KeyPair generateRsaKey() {KeyPair keyPair;try {KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");keyPairGenerator.initialize(2048);keyPair = keyPairGenerator.generateKeyPair();} catch (Exception ex) {throw new IllegalStateException(ex);}return keyPair;}@Bean@Order(1)public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http)throws Exception {// 默认配置OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);OAuth2AuthorizationServerConfigurer authorizationServerConfigurer = new OAuth2AuthorizationServerConfigurer();http.apply(authorizationServerConfigurer)// Enable OpenID Connect 1.0.oidc(Customizer.withDefaults())// 在这加上密码模式的转换器.tokenEndpoint(tokenEndpoint -> tokenEndpoint.accessTokenRequestConverter(new DelegatingAuthenticationConverter(Arrays.asList(new OAuth2AuthorizationCodeAuthenticationConverter(),new OAuth2RefreshTokenAuthenticationConverter(),new OAuth2ClientCredentialsAuthenticationConverter(),new OpenAuthPasswordAuthenticationConverter()))));http// Redirect to the login page when not authenticated from the// authorization endpoint.exceptionHandling((exceptions) -> exceptions.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login")))// Accept access tokens for User Info and/or Client Registration.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);// 先buildDefaultSecurityFilterChain securityFilterChain = http.requestMatcher(authorizationServerConfigurer.getEndpointsMatcher())// 这个必须禁用.csrf().disable().build();// 密码模式的认证提供者addPasswordAuthenticationProvider(http);return securityFilterChain;}@Bean@Order(2)public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http)throws Exception {http.authorizeHttpRequests().antMatchers("/assets/**", "/webjars/**", "/login", "/favicon.ico").permitAll().anyRequest().authenticated().and()// Form login handles the redirect to the login page from the// authorization server filter chain.formLogin().loginPage("/login").loginProcessingUrl("/login");//		// 资源服务器
//		http.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);return http.build();}@Beanpublic UserDetailsService userDetailsService() {UserDetails userDetails = User.builder().username("admin").password("{noop}admin").roles("ADMIN").build();return new InMemoryUserDetailsManager(userDetails);}@Beanpublic RegisteredClientRepository registeredClientRepository() {RegisteredClient registeredClient = RegisteredClient.withId(UUID.randomUUID().toString()).clientId("messaging-client").clientSecret("{noop}secret").clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC).authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE).authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN).authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)// 密码模式.authorizationGrantType(AuthorizationGrantType.PASSWORD).redirectUri("http://127.0.0.1:8080/login/oauth2/code/messaging-client-oidc").redirectUri("http://127.0.0.1:8080/authorized").redirectUri("https://baidu.com").scope(OidcScopes.OPENID).scope(OidcScopes.PROFILE).scope("message.read").scope("message.write").tokenSettings(TokenSettings.builder().accessTokenTimeToLive(Duration.ofHours(1L)).build())
//				.clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build()).build();return new InMemoryRegisteredClientRepository(registeredClient);}@Beanpublic JWKSource<SecurityContext> jwkSource() {KeyPair keyPair = generateRsaKey();RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();RSAKey rsaKey = new RSAKey.Builder(publicKey).privateKey(privateKey).keyID(UUID.randomUUID().toString()).build();JWKSet jwkSet = new JWKSet(rsaKey);return new ImmutableJWKSet<>(jwkSet);}@Beanpublic JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);}@Beanpublic AuthorizationServerSettings authorizationServerSettings() {return AuthorizationServerSettings.builder().build();}@SuppressWarnings("unchecked")private void addPasswordAuthenticationProvider(HttpSecurity http) {AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManager.class);OAuth2AuthorizationService authorizationService = http.getSharedObject(OAuth2AuthorizationService.class);OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator = http.getSharedObject(OAuth2TokenGenerator.class);OpenAuthPasswordAuthenticationProvider resourceOwnerPasswordAuthenticationProvider =new OpenAuthPasswordAuthenticationProvider(authenticationManager, authorizationService, tokenGenerator);// This will add new authentication provider in the list of existing authentication providers.http.authenticationProvider(resourceOwnerPasswordAuthenticationProvider);}}
  • DemoAuthApplication
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;/**** @author qiudw* @date 6/7/2023*/
@SpringBootApplication
public class DemoAuthApplication {public static void main(String[] args) {SpringApplication.run(DemoAuthApplication.class, args);}}
  • LoginController
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;/*** 登录相关** @author qiudw* @date 5/17/2023*/
@Controller
public class LoginController {/*** 登录页面** @return 登录页面路径*/@GetMapping("/login")public String login() {return "login";}}
  • login.html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Login</title>
</head>
<body>
<form th:action="@{/login}" method="post"><input type="text" name="username" placeholder="用户名" /> <br/><input type="password" name="password" placeholder="密码" /> <br/><button type="submit">登录</button> <br/>
</form>
</body>
</html>
  • application.yml
server:port: 9000

测试案例

授权码模式的时候重定向地址是百度

### 授权码模式:浏览器 - 获取授权码
http://127.0.0.1:9000/oauth2/authorize?response_type=code&client_id=messaging-client&redirect_uri=https://baidu.com&scope=message.read message.write openid### 授权码模式:使用授权码换取token
POST http://127.0.0.1:9000/oauth2/token
Content-Type: application/x-www-form-urlencoded
# 这个是base64(${clientId}:${clientSecret})
Authorization: Basic bWVzc2FnaW5nLWNsaWVudDpzZWNyZXQ=grant_type=authorization_code&redirect_uri=https://baidu.com&code=WQfVvh3eP1tTifBHiKgZd5iifsVhA4t5QSPOv8YAWFRur-X5hiMXL7rY54LFGR0oXs1SWcycnt-8kxPquVnYCA-e3RYcfdg7Rq_q0M3K0Gws7Er1N1dC2lnJRKRUKpO3### 刷新token
POST http://127.0.0.1:9000/oauth2/token
Content-Type: application/x-www-form-urlencoded
# 这个是base64(${clientId}:${clientSecret})
Authorization: Basic bWVzc2FnaW5nLWNsaWVudDpzZWNyZXQ=grant_type=refresh_token&refresh_token=7q5syxjItfPD-w63zo7mjIRCHhvo15fz5xybmYQJe9unXOXn12MjhgH0Ckrkysut3eq1SyaJYxm6l-SLeSFjoS-8kHrovGEUH54pb8UE_TbgR0BPhvV01-1CngQeGNwv### 客户端模式
POST http://127.0.0.1:9000/oauth2/token
Content-Type: application/x-www-form-urlencoded
Authorization: Basic bWVzc2FnaW5nLWNsaWVudDpzZWNyZXQ=grant_type=client_credentials### 密码模式
POST http://127.0.0.1:9000/oauth2/token
Content-Type: application/x-www-form-urlencoded
Authorization: Basic bWVzc2FnaW5nLWNsaWVudDpzZWNyZXQ=grant_type=password&username=admin&password=admin### 获取用户
POST http://127.0.0.1:9000/userinfo
# access_token
Authorization: Bearer eyJraWQiOiIzMTk4MzQwMC03OTMzLTQxMTMtYTE4Ni0wMDg3NTgyNWQ0MTkiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsImF1ZCI6Im1lc3NhZ2luZy1jbGllbnQiLCJuYmYiOjE2ODYxMjk5NDIsInNjb3BlIjpbIm9wZW5pZCIsIm1lc3NhZ2UucmVhZCIsIm1lc3NhZ2Uud3JpdGUiXSwiaXNzIjoiaHR0cDovLzEyNy4wLjAuMTo5MDAwIiwiZXhwIjoxNjg2MTMzNTQyLCJpYXQiOjE2ODYxMjk5NDJ9.a_ya4kRqOx3iCn27QdxpCg0h8etgYGcPqDjVFWbzmieQ1oUHZuVCsxcJcioewp9tmRQ-NwVL86mQBWNwLxQ555fhqTAAjzFg1-obKFS_RoulOIyNkTMgjL7oUV_p-_L7BQLLqvE_E57-8V_dvsZn7xQavY4TbwHH2QNWVCDKS807CmdOJErE7idsEZZbiyHtB0JcGn7VAfBHCpVyADN8HzgZVEtfuOtrgBGTOpypNJwb0kADgd7661l4P2hBSaInUI-m0m-I1-E-Q47lM0WAUtwHUusavxsd7ADEYNSAHgc3-s8ME4yqvRwrPIfuhWejYPm4WVoC04c5dvcnAIlDDg### 获取可用端点
GET http://127.0.0.1:9000/.well-known/oauth-authorization-server### 获取可用端点
GET http://127.0.0.1:9000/.well-known/openid-configuration### 吊销令牌
POST http://127.0.0.1:9000/oauth2/revoke
Content-Type: application/x-www-form-urlencoded
Authorization: Basic bWVzc2FnaW5nLWNsaWVudDpzZWNyZXQ=#token_type_hint=refresh_token&token=klA-i51s2hVbankpkg9kRh9jk1EIFJnwHhdAYHbS7LoW9YBwMRvqSShOL_8h_LgunSytWh-08JveyLedHfAUD8ovrTjled6i7HYIgwKQUSP18zUTCThs-HV8AeboTtfX
token_type_hint=access_token&token=eyJraWQiOiIzMTk4MzQwMC03OTMzLTQxMTMtYTE4Ni0wMDg3NTgyNWQ0MTkiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsImF1ZCI6Im1lc3NhZ2luZy1jbGllbnQiLCJuYmYiOjE2ODYxMjk5NjEsInNjb3BlIjpbIm9wZW5pZCIsInByb2ZpbGUiLCJtZXNzYWdlLnJlYWQiLCJtZXNzYWdlLndyaXRlIl0sImlzcyI6Imh0dHA6Ly8xMjcuMC4wLjE6OTAwMCIsImV4cCI6MTY4NjEzMzU2MSwiaWF0IjoxNjg2MTI5OTYxfQ.k66ovHpVKiEqRWlotffiDPdrcni8ltuhLkhI8Evg6WZd4xc7GzqIAtL5qqAXsW0o4FjSaqTSKkrkjcAzcPx3dgatCjhHrY7_FleywRBHrvpY0rH5MJMWsoQourdBa0SIO5WwlOZwiC_OVArF5rzTZldG-e0Skpbh8PppzfIMWQ1usSyGMxlJMKXkVOjumCKJu_JWrj3gAzTPfSbJS5ikPx0G6t5GXvKnBKQXKWr-umabharF5IZQ2jEctlIAllm_EoAA1YtzfbQPRkATjXY0mYJboemaF0FsDoOQDpbA5VU6pPuM6sxfv64D1wNcFR0HO6vuWYRR9k3XqIUjGgL_Ig

授权码模式重定向
在这里插入图片描述

密码模式
在这里插入图片描述

客户端模式
在这里插入图片描述

拿到这里access_token,可以解析出来看看https://tool.box3.cn/jwt.html
在这里插入图片描述
客户端模式获取的access_token,这个认证主体是客户端id

在这里插入图片描述
授权码和密码模式获取的access_token,认证主体就是登录的用户名。

http://www.jmfq.cn/news/4729051.html

相关文章:

  • 网站测试问题提交模板/台州专业关键词优化
  • 为什么要建设就业指导网站/关键词推广方法
  • 汕头网站公司/seo优化网站优化排名
  • 海淘手表网站/网页设计是干嘛的
  • 网站权限怎么弄/中国纪检监察报
  • 四川省住房和城乡建设厅官网站网/比较靠谱的网站
  • 用网站做的简历/seo自动优化工具
  • 北京联通网站备案/搜索引擎搜索器
  • 邀人做任务比较好的发布网站/淘宝关键词排名
  • java网站开发框架搭建/电商推广和网络推广的策略
  • 深圳网站建设迅美/抖音关键词排名系统
  • windows搭建网站开发/推广游戏怎么拉人最快
  • 做网站java好还是.net好/网络推广经验
  • 河南省城乡和住房建设厅网站/福州关键词快速排名
  • 莱芜市莱城区城乡建设局网站/百度视频下载
  • 如何做快递api接口网站/外贸seo网站建设
  • wordpress缩略图采集火车头/重庆seo优
  • 世界建筑网站/网络搜索关键词排名
  • 网站建设网站定制开发/seo推广方案
  • 杭州企业公司网页设计/池州网站seo
  • 网站策划建站/百度商城
  • 建设网站 费用/外贸营销网站怎么建站
  • 专业做化妆品外包材的招聘网站/seo实战优化
  • 工商工事上哪个网站做/淘宝指数
  • 网站开发常用语言比较/聚合搜索引擎
  • 网站制作常见问题 图片版权/搜索引擎营销的优缺点
  • 福州专业网站设计/网络广告策划书模板范文
  • 提供温州手机网站制作哪家好/惠州seo关键词排名
  • 苏州住房和城乡建设厅网站/会计培训班哪个机构比较好
  • 新的网站设计制作/seo基础教程