mirror of
https://gitee.com/log4j/pig.git
synced 2024-12-22 20:54:25 +08:00
扩展密码模式,增加sql
This commit is contained in:
parent
ebe9e1f9dc
commit
bcd544b309
81
db/auth.sql
Normal file
81
db/auth.sql
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
SET NAMES utf8mb4;
|
||||||
|
SET FOREIGN_KEY_CHECKS = 0;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for oauth2_authorization
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `oauth2_authorization`;
|
||||||
|
CREATE TABLE `oauth2_authorization` (
|
||||||
|
`id` varchar(100) NOT NULL,
|
||||||
|
`registered_client_id` varchar(100) NOT NULL,
|
||||||
|
`principal_name` varchar(200) NOT NULL,
|
||||||
|
`authorization_grant_type` varchar(100) NOT NULL,
|
||||||
|
`attributes` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci,
|
||||||
|
`state` varchar(500) DEFAULT NULL,
|
||||||
|
`authorization_code_value` blob,
|
||||||
|
`authorization_code_issued_at` timestamp NULL DEFAULT NULL,
|
||||||
|
`authorization_code_expires_at` timestamp NULL DEFAULT NULL,
|
||||||
|
`authorization_code_metadata` varchar(2000) DEFAULT NULL,
|
||||||
|
`access_token_value` blob,
|
||||||
|
`access_token_issued_at` timestamp NULL DEFAULT NULL,
|
||||||
|
`access_token_expires_at` timestamp NULL DEFAULT NULL,
|
||||||
|
`access_token_metadata` varchar(2000) DEFAULT NULL,
|
||||||
|
`access_token_type` varchar(100) DEFAULT NULL,
|
||||||
|
`access_token_scopes` varchar(1000) DEFAULT NULL,
|
||||||
|
`oidc_id_token_value` blob,
|
||||||
|
`oidc_id_token_issued_at` timestamp NULL DEFAULT NULL,
|
||||||
|
`oidc_id_token_expires_at` timestamp NULL DEFAULT NULL,
|
||||||
|
`oidc_id_token_metadata` varchar(2000) DEFAULT NULL,
|
||||||
|
`refresh_token_value` blob,
|
||||||
|
`refresh_token_issued_at` timestamp NULL DEFAULT NULL,
|
||||||
|
`refresh_token_expires_at` timestamp NULL DEFAULT NULL,
|
||||||
|
`refresh_token_metadata` varchar(2000) DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for oauth2_authorization_consent
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `oauth2_authorization_consent`;
|
||||||
|
CREATE TABLE `oauth2_authorization_consent` (
|
||||||
|
`registered_client_id` varchar(100) NOT NULL,
|
||||||
|
`principal_name` varchar(200) NOT NULL,
|
||||||
|
`authorities` varchar(1000) NOT NULL,
|
||||||
|
PRIMARY KEY (`registered_client_id`,`principal_name`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of oauth2_authorization_consent
|
||||||
|
-- ----------------------------
|
||||||
|
BEGIN;
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for oauth2_registered_client
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `oauth2_registered_client`;
|
||||||
|
CREATE TABLE `oauth2_registered_client` (
|
||||||
|
`id` varchar(100) NOT NULL,
|
||||||
|
`client_id` varchar(100) NOT NULL,
|
||||||
|
`client_id_issued_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
`client_secret` varchar(200) DEFAULT NULL,
|
||||||
|
`client_secret_expires_at` timestamp NULL DEFAULT NULL,
|
||||||
|
`client_name` varchar(200) NOT NULL,
|
||||||
|
`client_authentication_methods` varchar(1000) NOT NULL,
|
||||||
|
`authorization_grant_types` varchar(1000) NOT NULL,
|
||||||
|
`redirect_uris` varchar(1000) DEFAULT NULL,
|
||||||
|
`scopes` varchar(1000) NOT NULL,
|
||||||
|
`client_settings` varchar(2000) NOT NULL,
|
||||||
|
`token_settings` varchar(2000) NOT NULL,
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of oauth2_registered_client
|
||||||
|
-- ----------------------------
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO `oauth2_registered_client` VALUES ('jumuning', 'jumuning', '2021-11-24 10:39:41', '{bcrypt}$2a$10$aNZ7R/TpKdRBrPT/gl7Avur0mj.1MAwbz47RT1Lm0sNZm51K4WFvC', NULL, 'jumuning', 'client_secret_post,client_secret_basic', 'refresh_token,client_credentials,password,authorization_code', 'https://www.baidu.com', 'message.read,role.admin', '{\"@class\":\"java.util.Collections$UnmodifiableMap\",\"settings.client.require-proof-key\":false,\"settings.client.require-authorization-consent\":false}', '{\"@class\":\"java.util.Collections$UnmodifiableMap\",\"settings.token.reuse-refresh-tokens\":true,\"settings.token.id-token-signature-algorithm\":[\"org.springframework.security.oauth2.jose.jws.SignatureAlgorithm\",\"RS256\"],\"settings.token.access-token-time-to-live\":[\"java.time.Duration\",3600.000000000],\"settings.token.refresh-token-time-to-live\":[\"java.time.Duration\",3600.000000000]}');
|
||||||
|
INSERT INTO `oauth2_registered_client` VALUES ('pig', 'pig', '2021-11-24 16:35:24', '{bcrypt}$2a$10$oKyVIM.bR8Bjt5PCMZzRJedqEfaQkUhfLkbxpNfM8xPS/JnjtVFZ2', NULL, 'pig', 'client_secret_post,client_secret_basic', 'refresh_token,client_credentials,password,authorization_code', 'https://pig4cloud.com', 'message.read,message.write', '{\"@class\":\"java.util.Collections$UnmodifiableMap\",\"settings.client.require-proof-key\":false,\"settings.client.require-authorization-consent\":false}', '{\"@class\":\"java.util.Collections$UnmodifiableMap\",\"settings.token.reuse-refresh-tokens\":true,\"settings.token.id-token-signature-algorithm\":[\"org.springframework.security.oauth2.jose.jws.SignatureAlgorithm\",\"RS256\"],\"settings.token.access-token-time-to-live\":[\"java.time.Duration\",10800.000000000],\"settings.token.refresh-token-time-to-live\":[\"java.time.Duration\",10800.000000000]}');
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
|
SET FOREIGN_KEY_CHECKS = 1;
|
@ -17,25 +17,37 @@
|
|||||||
package com.pig4cloud.pig.auth.config;
|
package com.pig4cloud.pig.auth.config;
|
||||||
|
|
||||||
import com.nimbusds.jose.jwk.source.JWKSource;
|
import com.nimbusds.jose.jwk.source.JWKSource;
|
||||||
|
import com.pig4cloud.pig.auth.support.OAuth2ResourceOwnerPasswordAuthenticationConverter;
|
||||||
|
import com.pig4cloud.pig.auth.support.OAuth2ResourceOwnerPasswordAuthenticationProvider;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.core.Ordered;
|
import org.springframework.core.Ordered;
|
||||||
import org.springframework.core.annotation.Order;
|
import org.springframework.core.annotation.Order;
|
||||||
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
import org.springframework.security.config.Customizer;
|
import org.springframework.security.config.Customizer;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
import org.springframework.security.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
|
import org.springframework.security.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
|
||||||
|
import org.springframework.security.config.annotation.web.configurers.oauth2.server.authorization.OAuth2AuthorizationServerConfigurer;
|
||||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||||
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
|
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
|
||||||
import org.springframework.security.oauth2.core.OAuth2TokenFormat;
|
import org.springframework.security.oauth2.core.OAuth2TokenFormat;
|
||||||
import org.springframework.security.oauth2.jwt.JwtEncoder;
|
import org.springframework.security.oauth2.jwt.JwtEncoder;
|
||||||
import org.springframework.security.oauth2.jwt.NimbusJwtEncoder;
|
import org.springframework.security.oauth2.jwt.NimbusJwtEncoder;
|
||||||
|
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.InMemoryRegisteredClientRepository;
|
||||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
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.client.RegisteredClientRepository;
|
||||||
import org.springframework.security.oauth2.server.authorization.config.ProviderSettings;
|
import org.springframework.security.oauth2.server.authorization.config.ProviderSettings;
|
||||||
import org.springframework.security.oauth2.server.authorization.config.TokenSettings;
|
import org.springframework.security.oauth2.server.authorization.config.TokenSettings;
|
||||||
import org.springframework.security.oauth2.server.authorization.token.*;
|
import org.springframework.security.oauth2.server.authorization.token.*;
|
||||||
|
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.web.SecurityFilterChain;
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
|
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author lengleng
|
* @author lengleng
|
||||||
@ -44,32 +56,43 @@ import org.springframework.security.web.SecurityFilterChain;
|
|||||||
@Configuration(proxyBeanMethods = false)
|
@Configuration(proxyBeanMethods = false)
|
||||||
public class AuthorizationServerConfiguration {
|
public class AuthorizationServerConfiguration {
|
||||||
|
|
||||||
|
private static final String CUSTOM_CONSENT_PAGE_URI = "/oauth2/login";
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定义 Spring Security 的拦截器链,比如我们的 授权url、获取token的url 需要由那个过滤器来处理,此处配置这个。 1.开放oauth2
|
||||||
|
* 相关地址 2.增加密码模式的扩展 方法 addCustomOAuth2ResourceOwnerPasswordAuthenticationProvider
|
||||||
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||||
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
|
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
|
||||||
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
|
OAuth2AuthorizationServerConfigurer<HttpSecurity> authorizationServerConfigurer = new OAuth2AuthorizationServerConfigurer<>();
|
||||||
|
|
||||||
return http.formLogin(Customizer.withDefaults()).build();
|
http.apply(authorizationServerConfigurer.tokenEndpoint(
|
||||||
|
(tokenEndpoint) -> tokenEndpoint.accessTokenRequestConverter(new DelegatingAuthenticationConverter(
|
||||||
|
Arrays.asList(new OAuth2AuthorizationCodeAuthenticationConverter(),
|
||||||
|
new OAuth2RefreshTokenAuthenticationConverter(),
|
||||||
|
new OAuth2ClientCredentialsAuthenticationConverter(),
|
||||||
|
new OAuth2ResourceOwnerPasswordAuthenticationConverter())))));
|
||||||
|
authorizationServerConfigurer.authorizationEndpoint(
|
||||||
|
authorizationEndpoint -> authorizationEndpoint.consentPage(CUSTOM_CONSENT_PAGE_URI));
|
||||||
|
|
||||||
|
RequestMatcher endpointsMatcher = authorizationServerConfigurer.getEndpointsMatcher();
|
||||||
|
|
||||||
|
http.requestMatcher(endpointsMatcher)
|
||||||
|
.authorizeRequests(authorizeRequests -> authorizeRequests.anyRequest().authenticated())
|
||||||
|
.csrf(csrf -> csrf.ignoringRequestMatchers(endpointsMatcher)).apply(authorizationServerConfigurer);
|
||||||
|
|
||||||
|
SecurityFilterChain securityFilterChain = http.formLogin(Customizer.withDefaults()).build();
|
||||||
|
|
||||||
|
// Custom configuration for Resource Owner Password grant type. Current
|
||||||
|
// implementation has no support for Resource Owner
|
||||||
|
// Password grant type
|
||||||
|
addCustomOAuth2PasswordAuthenticationProvider(http);
|
||||||
|
|
||||||
|
return securityFilterChain;
|
||||||
}
|
}
|
||||||
|
|
||||||
// @formatter:off
|
|
||||||
@Bean
|
|
||||||
public RegisteredClientRepository registeredClientRepository() {
|
|
||||||
RegisteredClient client = RegisteredClient.withId("pig")
|
|
||||||
.clientId("pig")
|
|
||||||
.clientSecret("{noop}pig")
|
|
||||||
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
|
|
||||||
.authorizationGrantTypes(authorizationGrantTypes -> {
|
|
||||||
authorizationGrantTypes.add(AuthorizationGrantType.AUTHORIZATION_CODE);
|
|
||||||
authorizationGrantTypes.add(AuthorizationGrantType.REFRESH_TOKEN);
|
|
||||||
})
|
|
||||||
.tokenSettings(TokenSettings.builder().accessTokenFormat(OAuth2TokenFormat.SELF_CONTAINED).build())
|
|
||||||
.redirectUri("https://pig4cloud.com")
|
|
||||||
.build();
|
|
||||||
return new InMemoryRegisteredClientRepository(client);
|
|
||||||
}
|
|
||||||
|
|
||||||
// @formatter:on
|
|
||||||
@Bean
|
@Bean
|
||||||
public OAuth2TokenGenerator tokenGenerator(JWKSource jwkSource) {
|
public OAuth2TokenGenerator tokenGenerator(JWKSource jwkSource) {
|
||||||
JwtEncoder jwtEncoder = new NimbusJwtEncoder(jwkSource);
|
JwtEncoder jwtEncoder = new NimbusJwtEncoder(jwkSource);
|
||||||
@ -84,4 +107,23 @@ public class AuthorizationServerConfiguration {
|
|||||||
return ProviderSettings.builder().build();
|
return ProviderSettings.builder().build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 扩展密码模式
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("all")
|
||||||
|
private void addCustomOAuth2PasswordAuthenticationProvider(HttpSecurity http) {
|
||||||
|
|
||||||
|
AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManager.class);
|
||||||
|
OAuth2TokenGenerator oAuth2TokenGenerator = http.getSharedObject(OAuth2TokenGenerator.class);
|
||||||
|
OAuth2AuthorizationService authorizationService = http.getSharedObject(OAuth2AuthorizationService.class);
|
||||||
|
|
||||||
|
OAuth2ResourceOwnerPasswordAuthenticationProvider resourceOwnerPasswordAuthenticationProvider =
|
||||||
|
new OAuth2ResourceOwnerPasswordAuthenticationProvider(authenticationManager,authorizationService,oAuth2TokenGenerator);
|
||||||
|
|
||||||
|
// This will add new authentication provider in the list of existing authentication providers.
|
||||||
|
http.authenticationProvider(resourceOwnerPasswordAuthenticationProvider);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -46,15 +46,4 @@ public class WebSecurityConfiguration {
|
|||||||
return http.build();
|
return http.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// @formatter:off
|
|
||||||
@Bean
|
|
||||||
UserDetailsService users() {
|
|
||||||
UserDetails user = User.builder()
|
|
||||||
.username("admin")
|
|
||||||
.password("{noop}123456")
|
|
||||||
.roles("USER")
|
|
||||||
.build();
|
|
||||||
return new InMemoryUserDetailsManager(user);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,165 +1,165 @@
|
|||||||
package com.pig4cloud.pig.auth.endpoint;
|
//package com.pig4cloud.pig.auth.endpoint;
|
||||||
|
//
|
||||||
import cn.hutool.core.util.StrUtil;
|
//import cn.hutool.core.util.StrUtil;
|
||||||
import cn.hutool.extra.spring.SpringUtil;
|
//import cn.hutool.extra.spring.SpringUtil;
|
||||||
import com.pig4cloud.pig.common.core.constant.SecurityConstants;
|
//import com.pig4cloud.pig.common.core.constant.SecurityConstants;
|
||||||
import com.pig4cloud.pig.common.core.util.R;
|
//import com.pig4cloud.pig.common.core.util.R;
|
||||||
import com.pig4cloud.pig.common.security.service.PigUserDetailsService;
|
//import com.pig4cloud.pig.common.security.service.PigUserDetailsService;
|
||||||
import lombok.RequiredArgsConstructor;
|
//import lombok.RequiredArgsConstructor;
|
||||||
import lombok.SneakyThrows;
|
//import lombok.SneakyThrows;
|
||||||
import org.springframework.core.Ordered;
|
//import org.springframework.core.Ordered;
|
||||||
import org.springframework.http.HttpHeaders;
|
//import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.http.converter.HttpMessageConverter;
|
//import org.springframework.http.converter.HttpMessageConverter;
|
||||||
import org.springframework.http.server.ServletServerHttpResponse;
|
//import org.springframework.http.server.ServletServerHttpResponse;
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
//import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
import org.springframework.security.core.Authentication;
|
//import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
//import org.springframework.security.core.userdetails.UserDetails;
|
||||||
import org.springframework.security.oauth2.core.*;
|
//import org.springframework.security.oauth2.core.*;
|
||||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
|
//import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
|
||||||
import org.springframework.security.oauth2.core.http.converter.OAuth2AccessTokenResponseHttpMessageConverter;
|
//import org.springframework.security.oauth2.core.http.converter.OAuth2AccessTokenResponseHttpMessageConverter;
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
|
//import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
|
//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.OAuth2AccessTokenAuthenticationToken;
|
||||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
//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.client.RegisteredClientRepository;
|
||||||
import org.springframework.security.oauth2.server.authorization.token.DefaultOAuth2TokenContext;
|
//import org.springframework.security.oauth2.server.authorization.token.DefaultOAuth2TokenContext;
|
||||||
import org.springframework.security.oauth2.server.authorization.token.OAuth2RefreshTokenGenerator;
|
//import org.springframework.security.oauth2.server.authorization.token.OAuth2RefreshTokenGenerator;
|
||||||
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator;
|
//import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator;
|
||||||
import org.springframework.security.web.authentication.www.BasicAuthenticationConverter;
|
//import org.springframework.security.web.authentication.www.BasicAuthenticationConverter;
|
||||||
import org.springframework.util.CollectionUtils;
|
//import org.springframework.util.CollectionUtils;
|
||||||
import org.springframework.web.bind.annotation.*;
|
//import org.springframework.web.bind.annotation.*;
|
||||||
|
//
|
||||||
import javax.servlet.http.HttpServletRequest;
|
//import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
//import javax.servlet.http.HttpServletResponse;
|
||||||
import java.io.IOException;
|
//import java.io.IOException;
|
||||||
import java.time.temporal.ChronoUnit;
|
//import java.time.temporal.ChronoUnit;
|
||||||
import java.util.Comparator;
|
//import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
//import java.util.HashMap;
|
||||||
import java.util.Map;
|
//import java.util.Map;
|
||||||
import java.util.Optional;
|
//import java.util.Optional;
|
||||||
|
//
|
||||||
/**
|
///**
|
||||||
* 登录端点
|
// * 登录端点
|
||||||
*
|
// *
|
||||||
* @author lengleng
|
// * @author lengleng
|
||||||
* @date 2022/5/27
|
// * @date 2022/5/27
|
||||||
*/
|
// */
|
||||||
@RestController
|
//@RestController
|
||||||
@RequiredArgsConstructor
|
//@RequiredArgsConstructor
|
||||||
@RequestMapping("/oauth")
|
//@RequestMapping("/oauth")
|
||||||
public class LoginEndpoint {
|
//public class LoginEndpoint {
|
||||||
|
//
|
||||||
private final OAuth2AuthorizationService tokenService;
|
// private final OAuth2AuthorizationService tokenService;
|
||||||
|
//
|
||||||
private final RegisteredClientRepository registeredClientRepository;
|
// private final RegisteredClientRepository registeredClientRepository;
|
||||||
|
//
|
||||||
private final OAuth2TokenGenerator tokenGenerator;
|
// private final OAuth2TokenGenerator tokenGenerator;
|
||||||
|
//
|
||||||
private final HttpMessageConverter<OAuth2AccessTokenResponse> accessTokenHttpResponseConverter = new OAuth2AccessTokenResponseHttpMessageConverter();
|
// private final HttpMessageConverter<OAuth2AccessTokenResponse> accessTokenHttpResponseConverter = new OAuth2AccessTokenResponseHttpMessageConverter();
|
||||||
|
//
|
||||||
private final OAuth2RefreshTokenGenerator refreshTokenGenerator = new OAuth2RefreshTokenGenerator();
|
// private final OAuth2RefreshTokenGenerator refreshTokenGenerator = new OAuth2RefreshTokenGenerator();
|
||||||
|
//
|
||||||
private BasicAuthenticationConverter authenticationConverter = new BasicAuthenticationConverter();
|
// private BasicAuthenticationConverter authenticationConverter = new BasicAuthenticationConverter();
|
||||||
|
//
|
||||||
@SneakyThrows
|
// @SneakyThrows
|
||||||
@PostMapping("/token")
|
// @PostMapping("/token")
|
||||||
public void login(HttpServletRequest request, HttpServletResponse response, String username, String password) {
|
// public void login(HttpServletRequest request, HttpServletResponse response, String username, String password) {
|
||||||
|
//
|
||||||
// 获取请求header 中的basic 信息
|
// // 获取请求header 中的basic 信息
|
||||||
UsernamePasswordAuthenticationToken clientAuthentication = authenticationConverter.convert(request);
|
// UsernamePasswordAuthenticationToken clientAuthentication = authenticationConverter.convert(request);
|
||||||
RegisteredClient client = registeredClientRepository.findByClientId(clientAuthentication.getName());
|
// RegisteredClient client = registeredClientRepository.findByClientId(clientAuthentication.getName());
|
||||||
|
//
|
||||||
// 根据用户名查询用户
|
// // 根据用户名查询用户
|
||||||
Map<String, PigUserDetailsService> userDetailsServiceMap = SpringUtil
|
// Map<String, PigUserDetailsService> userDetailsServiceMap = SpringUtil
|
||||||
.getBeansOfType(PigUserDetailsService.class);
|
// .getBeansOfType(PigUserDetailsService.class);
|
||||||
Optional<PigUserDetailsService> optional = userDetailsServiceMap.values().stream()
|
// Optional<PigUserDetailsService> optional = userDetailsServiceMap.values().stream()
|
||||||
.filter(service -> service.support(client.getClientId(), AuthorizationGrantType.PASSWORD.getValue()))
|
// .filter(service -> service.support(client.getClientId(), AuthorizationGrantType.PASSWORD.getValue()))
|
||||||
.max(Comparator.comparingInt(Ordered::getOrder));
|
// .max(Comparator.comparingInt(Ordered::getOrder));
|
||||||
UserDetails userDetails = optional.get().loadUserByUsername(username);
|
// UserDetails userDetails = optional.get().loadUserByUsername(username);
|
||||||
|
//
|
||||||
// 生成accessToken
|
// // 生成accessToken
|
||||||
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails,
|
// UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails,
|
||||||
null);
|
// null);
|
||||||
DefaultOAuth2TokenContext.Builder builder = DefaultOAuth2TokenContext.builder().registeredClient(client)
|
// DefaultOAuth2TokenContext.Builder builder = DefaultOAuth2TokenContext.builder().registeredClient(client)
|
||||||
.principal(authenticationToken).tokenType(OAuth2TokenType.ACCESS_TOKEN)
|
// .principal(authenticationToken).tokenType(OAuth2TokenType.ACCESS_TOKEN)
|
||||||
.authorizationGrantType(AuthorizationGrantType.PASSWORD);
|
// .authorizationGrantType(AuthorizationGrantType.PASSWORD);
|
||||||
OAuth2Token generatedAccessToken = this.tokenGenerator.generate(builder.build());
|
// OAuth2Token generatedAccessToken = this.tokenGenerator.generate(builder.build());
|
||||||
OAuth2AccessToken accessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,
|
// OAuth2AccessToken accessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,
|
||||||
generatedAccessToken.getTokenValue(), generatedAccessToken.getIssuedAt(),
|
// generatedAccessToken.getTokenValue(), generatedAccessToken.getIssuedAt(),
|
||||||
generatedAccessToken.getExpiresAt(), builder.build().getAuthorizedScopes());
|
// generatedAccessToken.getExpiresAt(), builder.build().getAuthorizedScopes());
|
||||||
|
//
|
||||||
OAuth2Authorization.Builder authorizationBuilder = OAuth2Authorization.withRegisteredClient(client)
|
// OAuth2Authorization.Builder authorizationBuilder = OAuth2Authorization.withRegisteredClient(client)
|
||||||
.principalName(authenticationToken.getName()).authorizationGrantType(AuthorizationGrantType.PASSWORD);
|
// .principalName(authenticationToken.getName()).authorizationGrantType(AuthorizationGrantType.PASSWORD);
|
||||||
if (generatedAccessToken instanceof ClaimAccessor) {
|
// if (generatedAccessToken instanceof ClaimAccessor) {
|
||||||
authorizationBuilder.token(accessToken,
|
// authorizationBuilder.token(accessToken,
|
||||||
(metadata) -> metadata.put(OAuth2Authorization.Token.CLAIMS_METADATA_NAME,
|
// (metadata) -> metadata.put(OAuth2Authorization.Token.CLAIMS_METADATA_NAME,
|
||||||
((ClaimAccessor) generatedAccessToken).getClaims()));
|
// ((ClaimAccessor) generatedAccessToken).getClaims()));
|
||||||
}
|
// }
|
||||||
else {
|
// else {
|
||||||
authorizationBuilder.accessToken(accessToken);
|
// authorizationBuilder.accessToken(accessToken);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// 创建刷新令牌
|
// // 创建刷新令牌
|
||||||
OAuth2Token generatedRefreshToken = this.refreshTokenGenerator
|
// OAuth2Token generatedRefreshToken = this.refreshTokenGenerator
|
||||||
.generate(builder.tokenType(OAuth2TokenType.REFRESH_TOKEN)
|
// .generate(builder.tokenType(OAuth2TokenType.REFRESH_TOKEN)
|
||||||
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN).build());
|
// .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN).build());
|
||||||
authorizationBuilder.refreshToken((OAuth2RefreshToken) generatedRefreshToken);
|
// authorizationBuilder.refreshToken((OAuth2RefreshToken) generatedRefreshToken);
|
||||||
OAuth2Authorization authorization = authorizationBuilder.build();
|
// OAuth2Authorization authorization = authorizationBuilder.build();
|
||||||
|
//
|
||||||
// 保存认证信息
|
// // 保存认证信息
|
||||||
tokenService.save(authorization);
|
// tokenService.save(authorization);
|
||||||
|
//
|
||||||
// 对外输出
|
// // 对外输出
|
||||||
Map<String, Object> additionalParameters = new HashMap<>();
|
// Map<String, Object> additionalParameters = new HashMap<>();
|
||||||
additionalParameters.put("license", "pig");
|
// additionalParameters.put("license", "pig");
|
||||||
additionalParameters.put(SecurityConstants.DETAILS_USER, userDetails);
|
// additionalParameters.put(SecurityConstants.DETAILS_USER, userDetails);
|
||||||
OAuth2AccessTokenAuthenticationToken oAuth2AccessTokenAuthenticationToken = new OAuth2AccessTokenAuthenticationToken(
|
// OAuth2AccessTokenAuthenticationToken oAuth2AccessTokenAuthenticationToken = new OAuth2AccessTokenAuthenticationToken(
|
||||||
client, authenticationToken, accessToken, (OAuth2RefreshToken) generatedRefreshToken,
|
// client, authenticationToken, accessToken, (OAuth2RefreshToken) generatedRefreshToken,
|
||||||
additionalParameters);
|
// additionalParameters);
|
||||||
sendAccessTokenResponse(response, oAuth2AccessTokenAuthenticationToken);
|
// sendAccessTokenResponse(response, oAuth2AccessTokenAuthenticationToken);
|
||||||
|
//
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@GetMapping("/info")
|
// @GetMapping("/info")
|
||||||
public OAuth2Authorization info(String token) {
|
// public OAuth2Authorization info(String token) {
|
||||||
return tokenService.findByToken(token, OAuth2TokenType.ACCESS_TOKEN);
|
// return tokenService.findByToken(token, OAuth2TokenType.ACCESS_TOKEN);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private void sendAccessTokenResponse(HttpServletResponse response, Authentication authentication)
|
// private void sendAccessTokenResponse(HttpServletResponse response, Authentication authentication)
|
||||||
throws IOException {
|
// throws IOException {
|
||||||
|
//
|
||||||
OAuth2AccessTokenAuthenticationToken accessTokenAuthentication = (OAuth2AccessTokenAuthenticationToken) authentication;
|
// OAuth2AccessTokenAuthenticationToken accessTokenAuthentication = (OAuth2AccessTokenAuthenticationToken) authentication;
|
||||||
|
//
|
||||||
OAuth2AccessToken accessToken = accessTokenAuthentication.getAccessToken();
|
// OAuth2AccessToken accessToken = accessTokenAuthentication.getAccessToken();
|
||||||
OAuth2RefreshToken refreshToken = accessTokenAuthentication.getRefreshToken();
|
// OAuth2RefreshToken refreshToken = accessTokenAuthentication.getRefreshToken();
|
||||||
Map<String, Object> additionalParameters = accessTokenAuthentication.getAdditionalParameters();
|
// Map<String, Object> additionalParameters = accessTokenAuthentication.getAdditionalParameters();
|
||||||
|
//
|
||||||
OAuth2AccessTokenResponse.Builder builder = OAuth2AccessTokenResponse.withToken(accessToken.getTokenValue())
|
// OAuth2AccessTokenResponse.Builder builder = OAuth2AccessTokenResponse.withToken(accessToken.getTokenValue())
|
||||||
.tokenType(accessToken.getTokenType()).scopes(accessToken.getScopes());
|
// .tokenType(accessToken.getTokenType()).scopes(accessToken.getScopes());
|
||||||
if (accessToken.getIssuedAt() != null && accessToken.getExpiresAt() != null) {
|
// if (accessToken.getIssuedAt() != null && accessToken.getExpiresAt() != null) {
|
||||||
builder.expiresIn(ChronoUnit.SECONDS.between(accessToken.getIssuedAt(), accessToken.getExpiresAt()));
|
// builder.expiresIn(ChronoUnit.SECONDS.between(accessToken.getIssuedAt(), accessToken.getExpiresAt()));
|
||||||
}
|
// }
|
||||||
if (refreshToken != null) {
|
// if (refreshToken != null) {
|
||||||
builder.refreshToken(refreshToken.getTokenValue());
|
// builder.refreshToken(refreshToken.getTokenValue());
|
||||||
}
|
// }
|
||||||
if (!CollectionUtils.isEmpty(additionalParameters)) {
|
// if (!CollectionUtils.isEmpty(additionalParameters)) {
|
||||||
builder.additionalParameters(additionalParameters);
|
// builder.additionalParameters(additionalParameters);
|
||||||
}
|
// }
|
||||||
OAuth2AccessTokenResponse accessTokenResponse = builder.build();
|
// OAuth2AccessTokenResponse accessTokenResponse = builder.build();
|
||||||
ServletServerHttpResponse httpResponse = new ServletServerHttpResponse(response);
|
// ServletServerHttpResponse httpResponse = new ServletServerHttpResponse(response);
|
||||||
this.accessTokenHttpResponseConverter.write(accessTokenResponse, null, httpResponse);
|
// this.accessTokenHttpResponseConverter.write(accessTokenResponse, null, httpResponse);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@DeleteMapping("/logout")
|
// @DeleteMapping("/logout")
|
||||||
public R<Boolean> logout(@RequestHeader(value = HttpHeaders.AUTHORIZATION, required = false) String authHeader) {
|
// public R<Boolean> logout(@RequestHeader(value = HttpHeaders.AUTHORIZATION, required = false) String authHeader) {
|
||||||
if (StrUtil.isBlank(authHeader)) {
|
// if (StrUtil.isBlank(authHeader)) {
|
||||||
return R.ok();
|
// return R.ok();
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
String tokenValue = authHeader.replace(OAuth2AccessToken.TokenType.BEARER.getValue(), StrUtil.EMPTY).trim();
|
// String tokenValue = authHeader.replace(OAuth2AccessToken.TokenType.BEARER.getValue(), StrUtil.EMPTY).trim();
|
||||||
OAuth2Authorization oAuth2Authorization = tokenService.findByToken(tokenValue, OAuth2TokenType.ACCESS_TOKEN);
|
// OAuth2Authorization oAuth2Authorization = tokenService.findByToken(tokenValue, OAuth2TokenType.ACCESS_TOKEN);
|
||||||
tokenService.remove(oAuth2Authorization);
|
// tokenService.remove(oAuth2Authorization);
|
||||||
return R.ok();
|
// return R.ok();
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
}
|
//}
|
||||||
|
@ -0,0 +1,50 @@
|
|||||||
|
package com.pig4cloud.pig.auth.support;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author jumuning
|
||||||
|
* @description OAuth2 端点工具
|
||||||
|
*/
|
||||||
|
public class OAuth2EndpointUtils {
|
||||||
|
|
||||||
|
static final String ACCESS_TOKEN_REQUEST_ERROR_URI = "https://datatracker.ietf.org/doc/html/rfc6749#section-5.2";
|
||||||
|
|
||||||
|
private OAuth2EndpointUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
|
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) -> {
|
||||||
|
if (values.length > 0) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
package com.pig4cloud.pig.auth.support;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author jumuning
|
||||||
|
* @description OAuth2 异常信息
|
||||||
|
*/
|
||||||
|
public interface OAuth2ErrorCodesExpand {
|
||||||
|
|
||||||
|
/** 用户名未找到 */
|
||||||
|
String USERNAME_NOT_FOUND = "username_not_found";
|
||||||
|
|
||||||
|
/** 错误凭证 */
|
||||||
|
String BAD_CREDENTIALS = "bad_credentials";
|
||||||
|
|
||||||
|
/** 用户被锁 */
|
||||||
|
String USER_LOCKED = "user_locked";
|
||||||
|
|
||||||
|
/** 用户禁用 */
|
||||||
|
String USER_DISABLE = "user_disable";
|
||||||
|
|
||||||
|
/** 用户过期 */
|
||||||
|
String USER_EXPIRED = "user_expired";
|
||||||
|
|
||||||
|
/** 证书过期 */
|
||||||
|
String CREDENTIALS_EXPIRED = "credentials_expired";
|
||||||
|
|
||||||
|
/** scope 为空异常 */
|
||||||
|
String SCOPE_IS_EMPTY = "scope_is_empty";
|
||||||
|
|
||||||
|
/** 未知的登录异常 */
|
||||||
|
String UN_KNOW_LOGIN_ERROR = "un_know_login_error";
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,78 @@
|
|||||||
|
package com.pig4cloud.pig.auth.support;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author jumuning
|
||||||
|
* @date 2021/9/14 OAuth2 资源所有者密码认证转换器
|
||||||
|
*/
|
||||||
|
public class OAuth2ResourceOwnerPasswordAuthenticationConverter implements AuthenticationConverter {
|
||||||
|
|
||||||
|
@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,279 @@
|
|||||||
|
package com.pig4cloud.pig.auth.support;
|
||||||
|
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.springframework.context.support.MessageSourceAccessor;
|
||||||
|
import org.springframework.security.authentication.*;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.AuthenticationException;
|
||||||
|
import org.springframework.security.core.SpringSecurityMessageSource;
|
||||||
|
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||||
|
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.time.Instant;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author jumuning
|
||||||
|
* @description 处理用户名密码授权
|
||||||
|
*/
|
||||||
|
public class OAuth2ResourceOwnerPasswordAuthenticationProvider implements AuthenticationProvider {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LogManager.getLogger(OAuth2ResourceOwnerPasswordAuthenticationProvider.class);
|
||||||
|
|
||||||
|
private static final String ERROR_URI = "https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.2.1";
|
||||||
|
|
||||||
|
private final OAuth2AuthorizationService authorizationService;
|
||||||
|
|
||||||
|
private final OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator;
|
||||||
|
|
||||||
|
private final AuthenticationManager authenticationManager;
|
||||||
|
|
||||||
|
private final MessageSourceAccessor messages = new MessageSourceAccessor(new SpringSecurityMessageSource(),
|
||||||
|
Locale.CHINA);
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
private Supplier<String> refreshTokenGenerator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an {@code OAuth2AuthorizationCodeAuthenticationProvider} using the
|
||||||
|
* provided parameters.
|
||||||
|
* @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;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public void setRefreshTokenGenerator(Supplier<String> refreshTokenGenerator) {
|
||||||
|
Assert.notNull(refreshTokenGenerator, "refreshTokenGenerator cannot be null");
|
||||||
|
this.refreshTokenGenerator = refreshTokenGenerator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs authentication with the same contract as
|
||||||
|
* {@link AuthenticationManager#authenticate(Authentication)}
|
||||||
|
* .
|
||||||
|
* @param authentication the authentication request object.
|
||||||
|
* @return a fully authenticated object including credentials. May return
|
||||||
|
* <code>null</code> if the <code>AuthenticationProvider</code> is unable to support
|
||||||
|
* authentication of the passed <code>Authentication</code> object. In such a case,
|
||||||
|
* the next <code>AuthenticationProvider</code> that supports the presented
|
||||||
|
* <code>Authentication</code> class will be tried.
|
||||||
|
* @throws AuthenticationException if authentication fails.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||||
|
|
||||||
|
OAuth2ResourceOwnerPasswordAuthenticationToken resouceOwnerPasswordAuthentication = (OAuth2ResourceOwnerPasswordAuthenticationToken) authentication;
|
||||||
|
|
||||||
|
OAuth2ClientAuthenticationToken clientPrincipal = getAuthenticatedClientElseThrowInvalidClient(
|
||||||
|
resouceOwnerPasswordAuthentication);
|
||||||
|
|
||||||
|
RegisteredClient registeredClient = clientPrincipal.getRegisteredClient();
|
||||||
|
|
||||||
|
assert registeredClient != null;
|
||||||
|
if (!registeredClient.getAuthorizationGrantTypes().contains(AuthorizationGrantType.PASSWORD)) {
|
||||||
|
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.UNAUTHORIZED_CLIENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<String> authorizedScopes = registeredClient.getScopes();
|
||||||
|
// Default to configured scopes
|
||||||
|
if (!CollectionUtils.isEmpty(resouceOwnerPasswordAuthentication.getScopes())) {
|
||||||
|
for (String requestedScope : resouceOwnerPasswordAuthentication.getScopes()) {
|
||||||
|
if (!registeredClient.getScopes().contains(requestedScope)) {
|
||||||
|
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_SCOPE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
authorizedScopes = new LinkedHashSet<>(resouceOwnerPasswordAuthentication.getScopes());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new ScopeException(OAuth2ErrorCodesExpand.SCOPE_IS_EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, Object> additionalParameters = resouceOwnerPasswordAuthentication.getAdditionalParameters();
|
||||||
|
String username = (String) additionalParameters.get(OAuth2ParameterNames.USERNAME);
|
||||||
|
String password = (String) additionalParameters.get(OAuth2ParameterNames.PASSWORD);
|
||||||
|
|
||||||
|
try {
|
||||||
|
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
|
||||||
|
username, password);
|
||||||
|
LOGGER.debug("got usernamePasswordAuthenticationToken=" + usernamePasswordAuthenticationToken);
|
||||||
|
|
||||||
|
Authentication usernamePasswordAuthentication = authenticationManager
|
||||||
|
.authenticate(usernamePasswordAuthenticationToken);
|
||||||
|
|
||||||
|
// @formatter:off
|
||||||
|
DefaultOAuth2TokenContext.Builder tokenContextBuilder = DefaultOAuth2TokenContext.builder()
|
||||||
|
.registeredClient(registeredClient)
|
||||||
|
.principal(usernamePasswordAuthentication)
|
||||||
|
.providerContext(ProviderContextHolder.getProviderContext())
|
||||||
|
.authorizedScopes(authorizedScopes)
|
||||||
|
.authorizationGrantType(AuthorizationGrantType.PASSWORD)
|
||||||
|
.authorizationGrant(resouceOwnerPasswordAuthentication);
|
||||||
|
// @formatter:on
|
||||||
|
|
||||||
|
OAuth2Authorization.Builder authorizationBuilder = OAuth2Authorization
|
||||||
|
.withRegisteredClient(registeredClient).principalName(usernamePasswordAuthentication.getName())
|
||||||
|
.authorizationGrantType(AuthorizationGrantType.PASSWORD)
|
||||||
|
.attribute(OAuth2Authorization.AUTHORIZED_SCOPE_ATTRIBUTE_NAME, authorizedScopes);
|
||||||
|
|
||||||
|
// ----- 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());
|
||||||
|
if (generatedAccessToken instanceof ClaimAccessor) {
|
||||||
|
authorizationBuilder
|
||||||
|
.token(accessToken,
|
||||||
|
(metadata) -> metadata.put(OAuth2Authorization.Token.CLAIMS_METADATA_NAME,
|
||||||
|
((ClaimAccessor) generatedAccessToken).getClaims()))
|
||||||
|
.attribute(OAuth2Authorization.AUTHORIZED_SCOPE_ATTRIBUTE_NAME, authorizedScopes)
|
||||||
|
.attribute(Principal.class.getName(), usernamePasswordAuthentication);
|
||||||
|
}
|
||||||
|
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)) {
|
||||||
|
|
||||||
|
if (this.refreshTokenGenerator != null) {
|
||||||
|
Instant issuedAt = Instant.now();
|
||||||
|
Instant expiresAt = issuedAt.plus(registeredClient.getTokenSettings().getRefreshTokenTimeToLive());
|
||||||
|
refreshToken = new OAuth2RefreshToken(this.refreshTokenGenerator.get(), issuedAt, expiresAt);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
tokenContext = tokenContextBuilder.tokenType(OAuth2TokenType.REFRESH_TOKEN).build();
|
||||||
|
OAuth2Token generatedRefreshToken = this.tokenGenerator.generate(tokenContext);
|
||||||
|
if (!(generatedRefreshToken instanceof OAuth2RefreshToken)) {
|
||||||
|
OAuth2Error error = new OAuth2Error(OAuth2ErrorCodes.SERVER_ERROR,
|
||||||
|
"The token generator failed to generate the refresh token.", ERROR_URI);
|
||||||
|
throw new OAuth2AuthenticationException(error);
|
||||||
|
}
|
||||||
|
refreshToken = (OAuth2RefreshToken) generatedRefreshToken;
|
||||||
|
}
|
||||||
|
authorizationBuilder.refreshToken(refreshToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
OAuth2Authorization authorization = authorizationBuilder.build();
|
||||||
|
|
||||||
|
this.authorizationService.save(authorization);
|
||||||
|
|
||||||
|
LOGGER.debug("returning OAuth2AccessTokenAuthenticationToken");
|
||||||
|
|
||||||
|
// ----- 扩展 暴露信息 -----
|
||||||
|
Map<String, Object> objectMap = new HashMap<>();
|
||||||
|
objectMap.put(OAuth2ParameterNames.USERNAME, username);
|
||||||
|
|
||||||
|
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, accessToken,
|
||||||
|
refreshToken, objectMap);
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception ex) {
|
||||||
|
LOGGER.error("problem in authenticate", ex);
|
||||||
|
throw oAuth2AuthenticationException(authentication, (AuthenticationException) ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supports(Class<?> authentication) {
|
||||||
|
boolean supports = OAuth2ResourceOwnerPasswordAuthenticationToken.class.isAssignableFrom(authentication);
|
||||||
|
LOGGER.debug("supports authentication=" + authentication + " returning " + supports);
|
||||||
|
return supports;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录异常转换为oauth2异常
|
||||||
|
* @param authentication 身份验证
|
||||||
|
* @param authenticationException 身份验证异常
|
||||||
|
* @return {@link OAuth2AuthenticationException}
|
||||||
|
*/
|
||||||
|
private OAuth2AuthenticationException oAuth2AuthenticationException(Authentication authentication,
|
||||||
|
AuthenticationException authenticationException) {
|
||||||
|
if (authenticationException instanceof UsernameNotFoundException) {
|
||||||
|
return new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodesExpand.USERNAME_NOT_FOUND,
|
||||||
|
this.messages.getMessage("JdbcDaoImpl.notFound", new Object[] { authentication.getName() },
|
||||||
|
"Username {0} not found"),
|
||||||
|
""));
|
||||||
|
}
|
||||||
|
if (authenticationException instanceof BadCredentialsException) {
|
||||||
|
return new OAuth2AuthenticationException(
|
||||||
|
new OAuth2Error(OAuth2ErrorCodesExpand.BAD_CREDENTIALS, this.messages.getMessage(
|
||||||
|
"AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"), ""));
|
||||||
|
}
|
||||||
|
if (authenticationException instanceof LockedException) {
|
||||||
|
return new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodesExpand.USER_LOCKED, this.messages
|
||||||
|
.getMessage("AbstractUserDetailsAuthenticationProvider.locked", "User account is locked"), ""));
|
||||||
|
}
|
||||||
|
if (authenticationException instanceof DisabledException) {
|
||||||
|
return new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodesExpand.USER_DISABLE,
|
||||||
|
this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.disabled", "User is disabled"),
|
||||||
|
""));
|
||||||
|
}
|
||||||
|
if (authenticationException instanceof AccountExpiredException) {
|
||||||
|
return new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodesExpand.USER_EXPIRED, this.messages
|
||||||
|
.getMessage("AbstractUserDetailsAuthenticationProvider.expired", "User account has expired"), ""));
|
||||||
|
}
|
||||||
|
if (authenticationException instanceof CredentialsExpiredException) {
|
||||||
|
return new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodesExpand.CREDENTIALS_EXPIRED,
|
||||||
|
this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.credentialsExpired",
|
||||||
|
"User credentials have expired"),
|
||||||
|
""));
|
||||||
|
}
|
||||||
|
if (authenticationException instanceof ScopeException) {
|
||||||
|
return new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodes.INVALID_SCOPE,
|
||||||
|
this.messages.getMessage("AbstractAccessDecisionManager.accessDenied", "invalid_scope"), ""));
|
||||||
|
}
|
||||||
|
return new OAuth2AuthenticationException(OAuth2ErrorCodesExpand.UN_KNOW_LOGIN_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
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,80 @@
|
|||||||
|
package com.pig4cloud.pig.auth.support;
|
||||||
|
|
||||||
|
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.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author jumuning
|
||||||
|
* @description 密码授权token信息
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
package com.pig4cloud.pig.auth.support;
|
||||||
|
|
||||||
|
import org.springframework.security.core.AuthenticationException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author jumuning
|
||||||
|
* @description ScopeException 异常信息
|
||||||
|
*/
|
||||||
|
public class ScopeException extends AuthenticationException {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a <code>ScopeException</code> with the specified message.
|
||||||
|
* @param msg the detail message.
|
||||||
|
*/
|
||||||
|
public ScopeException(String msg) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a {@code ScopeException} with the specified message and root cause.
|
||||||
|
* @param msg the detail message.
|
||||||
|
* @param cause root cause
|
||||||
|
*/
|
||||||
|
public ScopeException(String msg, Throwable cause) {
|
||||||
|
super(msg, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -64,5 +64,9 @@
|
|||||||
<groupId>org.springframework</groupId>
|
<groupId>org.springframework</groupId>
|
||||||
<artifactId>spring-webmvc</artifactId>
|
<artifactId>spring-webmvc</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-jdbc</artifactId>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
@ -16,21 +16,88 @@
|
|||||||
|
|
||||||
package com.pig4cloud.pig.common.security.component;
|
package com.pig4cloud.pig.common.security.component;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.Module;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.pig4cloud.pig.admin.api.feign.RemoteUserService;
|
||||||
|
import com.pig4cloud.pig.common.security.service.PigUser;
|
||||||
|
import com.pig4cloud.pig.common.security.service.PigUserDetailsServiceImpl;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
import org.springframework.cache.CacheManager;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
|
import org.springframework.security.jackson2.SecurityJackson2Modules;
|
||||||
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
||||||
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
|
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationConsentService;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService;
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
|
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.client.JdbcRegisteredClientRepository;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.jackson2.OAuth2AuthorizationServerJackson2Module;
|
||||||
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector;
|
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector;
|
||||||
|
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author lengleng
|
* @author lengleng
|
||||||
* @date 2020-06-23
|
* @date 2020-06-23
|
||||||
*/
|
*/
|
||||||
@EnableConfigurationProperties(PermitAllUrlProperties.class)
|
@EnableConfigurationProperties(PermitAllUrlProperties.class)
|
||||||
|
@RequiredArgsConstructor
|
||||||
public class PigResourceServerAutoConfiguration {
|
public class PigResourceServerAutoConfiguration {
|
||||||
|
|
||||||
|
|
||||||
|
private final RemoteUserService remoteUserService;
|
||||||
|
|
||||||
|
private final CacheManager cacheManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配置授权服务器连接数据库,增加自定义序列化数据
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public OAuth2AuthorizationService authorizationService(JdbcTemplate jdbcTemplate,
|
||||||
|
RegisteredClientRepository registeredClientRepository) {
|
||||||
|
JdbcOAuth2AuthorizationService service = new JdbcOAuth2AuthorizationService(jdbcTemplate,
|
||||||
|
registeredClientRepository);
|
||||||
|
JdbcOAuth2AuthorizationService.OAuth2AuthorizationRowMapper rowMapper = new JdbcOAuth2AuthorizationService.OAuth2AuthorizationRowMapper(
|
||||||
|
registeredClientRepository);
|
||||||
|
|
||||||
|
ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
ClassLoader classLoader = JdbcOAuth2AuthorizationService.class.getClassLoader();
|
||||||
|
List<Module> securityModules = SecurityJackson2Modules.getModules(classLoader);
|
||||||
|
objectMapper.registerModules(securityModules);
|
||||||
|
objectMapper.registerModule(new OAuth2AuthorizationServerJackson2Module());
|
||||||
|
|
||||||
|
// You will need to write the Mixin for your class so Jackson can marshall it.
|
||||||
|
objectMapper.addMixIn(LinkedHashSet.class, LinkedHashSet.class);
|
||||||
|
objectMapper.addMixIn(PigUser.class, PigUser.class);
|
||||||
|
|
||||||
|
rowMapper.setObjectMapper(objectMapper);
|
||||||
|
service.setAuthorizationRowMapper(rowMapper);
|
||||||
|
|
||||||
|
return service;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public RegisteredClientRepository registeredClientRepository(JdbcTemplate jdbcTemplate) {
|
||||||
|
return new JdbcRegisteredClientRepository(jdbcTemplate);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 如果是授权码的流程,可能客户端申请了多个权限,比如:获取用户信息,修改用户信息, 此Service处理的是用户给这个客户端哪些权限,比如只给获取用户信息的权限
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public OAuth2AuthorizationConsentService authorizationConsentService(JdbcTemplate jdbcTemplate,
|
||||||
|
RegisteredClientRepository registeredClientRepository) {
|
||||||
|
return new JdbcOAuth2AuthorizationConsentService(jdbcTemplate, registeredClientRepository);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Bean("pms")
|
@Bean("pms")
|
||||||
public PermissionService permissionService() {
|
public PermissionService permissionService() {
|
||||||
return new PermissionService();
|
return new PermissionService();
|
||||||
@ -51,10 +118,18 @@ public class PigResourceServerAutoConfiguration {
|
|||||||
return new CustomOpaqueTokenIntrospector(authorizationService);
|
return new CustomOpaqueTokenIntrospector(authorizationService);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public UserDetailsService userDetailsService(){
|
||||||
|
return new PigUserDetailsServiceImpl(remoteUserService ,cacheManager);
|
||||||
|
}
|
||||||
|
|
||||||
// @Bean
|
// @Bean
|
||||||
public JwtDecoder jwtDecoder() {
|
public JwtDecoder jwtDecoder() {
|
||||||
NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withJwkSetUri("http://localhost:8080/auth/oauth2/jwks").build();
|
NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withJwkSetUri("http://localhost:8080/auth/oauth2/jwks").build();
|
||||||
return jwtDecoder;
|
return jwtDecoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -4,12 +4,8 @@ import com.nimbusds.jose.jwk.JWKSet;
|
|||||||
import com.nimbusds.jose.jwk.RSAKey;
|
import com.nimbusds.jose.jwk.RSAKey;
|
||||||
import com.nimbusds.jose.jwk.source.JWKSource;
|
import com.nimbusds.jose.jwk.source.JWKSource;
|
||||||
import com.nimbusds.jose.proc.SecurityContext;
|
import com.nimbusds.jose.proc.SecurityContext;
|
||||||
import com.pig4cloud.pig.common.security.service.PigRedisOAuth2AuthorizationService;
|
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
|
|
||||||
|
|
||||||
import java.security.KeyPair;
|
import java.security.KeyPair;
|
||||||
import java.security.KeyPairGenerator;
|
import java.security.KeyPairGenerator;
|
||||||
import java.security.interfaces.RSAPrivateKey;
|
import java.security.interfaces.RSAPrivateKey;
|
||||||
@ -22,10 +18,11 @@ import java.util.UUID;
|
|||||||
*/
|
*/
|
||||||
public class PigTokenStoreAutoConfiguration {
|
public class PigTokenStoreAutoConfiguration {
|
||||||
|
|
||||||
@Bean
|
//todo 暂时屏蔽redis 权限配置,存在不兼容的问题
|
||||||
public OAuth2AuthorizationService authorizationService(RedisTemplate redisTemplate) {
|
// @Bean
|
||||||
return new PigRedisOAuth2AuthorizationService(redisTemplate);
|
// public OAuth2AuthorizationService authorizationService(RedisTemplate redisTemplate) {
|
||||||
}
|
// return new PigRedisOAuth2AuthorizationService(redisTemplate);
|
||||||
|
// }
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
|
Loading…
Reference in New Issue
Block a user