mirror of
https://gitee.com/log4j/pig.git
synced 2024-12-22 20:54:25 +08:00
✨ Introducing new features. support sas 认证中心改造
This commit is contained in:
parent
64773a1f1a
commit
e4d9213c1e
157
pig-auth/pom.xml
157
pig-auth/pom.xml
@ -16,83 +16,92 @@
|
||||
-->
|
||||
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
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.pig4cloud</groupId>
|
||||
<artifactId>pig</artifactId>
|
||||
<version>3.4.10</version>
|
||||
</parent>
|
||||
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.pig4cloud</groupId>
|
||||
<artifactId>pig</artifactId>
|
||||
<version>3.4.10</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>pig-auth</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<artifactId>pig-auth</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<description>pig 认证授权中心,基于 spring security oAuth2</description>
|
||||
<description>pig 认证授权中心,基于 spring security oAuth2</description>
|
||||
|
||||
<dependencies>
|
||||
<!--注册中心客户端-->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
<!--配置中心客户端-->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
|
||||
</dependency>
|
||||
<!--断路器依赖-->
|
||||
<dependency>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pig-common-feign</artifactId>
|
||||
</dependency>
|
||||
<!--upms api、model 模块-->
|
||||
<dependency>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pig-upms-api</artifactId>
|
||||
</dependency>
|
||||
<!--security-->
|
||||
<dependency>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pig-common-security</artifactId>
|
||||
</dependency>
|
||||
<!--JDBC相关-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-jdbc</artifactId>
|
||||
</dependency>
|
||||
<!--freemarker-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-freemarker</artifactId>
|
||||
</dependency>
|
||||
<!--数据库-->
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
</dependency>
|
||||
<!--undertow容器-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-undertow</artifactId>
|
||||
</dependency>
|
||||
<!-- log -->
|
||||
<dependency>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pig-common-log</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<dependencies>
|
||||
<!--注册中心客户端-->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
<!--配置中心客户端-->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
|
||||
</dependency>
|
||||
<!--断路器依赖-->
|
||||
<dependency>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pig-common-feign</artifactId>
|
||||
</dependency>
|
||||
<!--upms api、model 模块-->
|
||||
<dependency>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pig-upms-api</artifactId>
|
||||
</dependency>
|
||||
<!--security-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-oauth2-authorization-server</artifactId>
|
||||
<version>0.3.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pig-common-security</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
<!--JDBC相关-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-jdbc</artifactId>
|
||||
</dependency>
|
||||
<!--freemarker-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-freemarker</artifactId>
|
||||
</dependency>
|
||||
<!--数据库-->
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
</dependency>
|
||||
<!--undertow容器-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-undertow</artifactId>
|
||||
</dependency>
|
||||
<!-- log -->
|
||||
<dependency>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pig-common-log</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>io.fabric8</groupId>
|
||||
<artifactId>docker-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>io.fabric8</groupId>
|
||||
<artifactId>docker-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
|
@ -16,50 +16,60 @@
|
||||
|
||||
package com.pig4cloud.pig.auth.config;
|
||||
|
||||
import com.pig4cloud.pig.common.core.constant.SecurityConstants;
|
||||
import com.pig4cloud.pig.common.security.component.PigWebResponseExceptionTranslator;
|
||||
import com.pig4cloud.pig.common.security.grant.ResourceOwnerCustomAppTokenGranter;
|
||||
import com.pig4cloud.pig.common.security.service.PigClientDetailsService;
|
||||
import com.pig4cloud.pig.common.security.service.PigCustomTokenServices;
|
||||
import com.pig4cloud.pig.common.security.service.PigUser;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import com.nimbusds.jose.jwk.source.JWKSource;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
|
||||
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
|
||||
import org.springframework.security.oauth2.provider.ClientDetailsService;
|
||||
import org.springframework.security.oauth2.provider.CompositeTokenGranter;
|
||||
import org.springframework.security.oauth2.provider.TokenGranter;
|
||||
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
|
||||
import org.springframework.security.oauth2.provider.token.TokenStore;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
|
||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
|
||||
import org.springframework.security.oauth2.core.OAuth2TokenFormat;
|
||||
import org.springframework.security.oauth2.jwt.JwtEncoder;
|
||||
import org.springframework.security.oauth2.jwt.NimbusJwtEncoder;
|
||||
import org.springframework.security.oauth2.server.authorization.InMemoryOAuth2AuthorizationService;
|
||||
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.ProviderSettings;
|
||||
import org.springframework.security.oauth2.server.authorization.config.TokenSettings;
|
||||
import org.springframework.security.oauth2.server.authorization.token.*;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
|
||||
/**
|
||||
* @author lengleng
|
||||
* @date 2022/5/27 认证服务器配置
|
||||
*/
|
||||
@Configuration
|
||||
@RequiredArgsConstructor
|
||||
@EnableAuthorizationServer
|
||||
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class AuthorizationServerConfiguration {
|
||||
|
||||
private final DataSource dataSource;
|
||||
@Bean
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
|
||||
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
|
||||
|
||||
private final AuthenticationManager authenticationManager;
|
||||
return http.formLogin(Customizer.withDefaults()).build();
|
||||
}
|
||||
|
||||
private final TokenStore redisTokenStore;
|
||||
// @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
|
||||
@ -71,31 +81,14 @@ public class AuthorizationServerConfiguration extends AuthorizationServerConfigu
|
||||
return new DelegatingOAuth2TokenGenerator(jwtGenerator, accessTokenGenerator, refreshTokenGenerator);
|
||||
}
|
||||
|
||||
/**
|
||||
* 客户端信息加载处理
|
||||
* @return ClientDetailsService
|
||||
*/
|
||||
@Bean
|
||||
public ClientDetailsService pigClientDetailsService() {
|
||||
PigClientDetailsService clientDetailsService = new PigClientDetailsService(dataSource);
|
||||
clientDetailsService.setSelectClientDetailsSql(SecurityConstants.DEFAULT_SELECT_STATEMENT);
|
||||
clientDetailsService.setFindClientDetailsSql(SecurityConstants.DEFAULT_FIND_STATEMENT);
|
||||
return clientDetailsService;
|
||||
public ProviderSettings providerSettings() {
|
||||
return ProviderSettings.builder().build();
|
||||
}
|
||||
|
||||
/**
|
||||
* token 核心处理
|
||||
* @return tokenServices
|
||||
*/
|
||||
@Bean
|
||||
public PigCustomTokenServices tokenServices() {
|
||||
PigCustomTokenServices tokenServices = new PigCustomTokenServices();
|
||||
tokenServices.setTokenStore(redisTokenStore);
|
||||
tokenServices.setSupportRefreshToken(true);
|
||||
tokenServices.setReuseRefreshToken(false);
|
||||
tokenServices.setClientDetailsService(pigClientDetailsService());
|
||||
tokenServices.setTokenEnhancer(tokenEnhancer());
|
||||
return tokenServices;
|
||||
public OAuth2AuthorizationService authorizationService() {
|
||||
return new InMemoryOAuth2AuthorizationService();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -16,102 +16,44 @@
|
||||
|
||||
package com.pig4cloud.pig.auth.config;
|
||||
|
||||
import com.pig4cloud.pig.common.security.component.PigDaoAuthenticationProvider;
|
||||
import com.pig4cloud.pig.common.security.grant.CustomAppAuthenticationProvider;
|
||||
import com.pig4cloud.pig.common.security.handler.FormAuthenticationFailureHandler;
|
||||
import com.pig4cloud.pig.common.security.handler.SsoLogoutSuccessHandler;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
|
||||
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
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.provisioning.InMemoryUserDetailsManager;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
|
||||
/**
|
||||
* @author lengleng
|
||||
* @date 2022/1/12 认证相关配置
|
||||
*/
|
||||
@Primary
|
||||
@Order(90)
|
||||
@Configuration
|
||||
@RequiredArgsConstructor
|
||||
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
protected void configure(HttpSecurity http) {
|
||||
http.formLogin().loginPage("/token/login").loginProcessingUrl("/token/form")
|
||||
.failureHandler(authenticationFailureHandler()).and().logout()
|
||||
.logoutSuccessHandler(logoutSuccessHandler()).deleteCookies("JSESSIONID").invalidateHttpSession(true)
|
||||
.and().authorizeRequests().antMatchers("/token/**", "/actuator/**", "/mobile/**").permitAll()
|
||||
.anyRequest().authenticated().and().csrf().disable();
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义 provider 列表注入
|
||||
* @param auth AuthenticationManagerBuilder
|
||||
*/
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) {
|
||||
PigDaoAuthenticationProvider daoAuthenticationProvider = new PigDaoAuthenticationProvider();
|
||||
daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());
|
||||
|
||||
// 处理默认的密码模式认证
|
||||
auth.authenticationProvider(daoAuthenticationProvider);
|
||||
// 自定义的认证模式
|
||||
auth.authenticationProvider(new CustomAppAuthenticationProvider());
|
||||
}
|
||||
@EnableWebSecurity
|
||||
public class WebSecurityConfiguration {
|
||||
|
||||
// @formatter:off
|
||||
@Bean
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public AuthenticationManager authenticationManagerBean() {
|
||||
return super.authenticationManagerBean();
|
||||
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests(authorizeRequests -> authorizeRequests
|
||||
.antMatchers("/password/*").permitAll()
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
.formLogin(Customizer.withDefaults());
|
||||
return http.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 认证中心静态资源处理
|
||||
* @param web WebSecurity
|
||||
*/
|
||||
@Override
|
||||
public void configure(WebSecurity web) {
|
||||
web.ignoring().antMatchers("/css/**", "/error");
|
||||
}
|
||||
|
||||
/**
|
||||
* sso 表单登录失败处理
|
||||
* @return FormAuthenticationFailureHandler
|
||||
*/
|
||||
// @formatter:off
|
||||
@Bean
|
||||
public AuthenticationFailureHandler authenticationFailureHandler() {
|
||||
return new FormAuthenticationFailureHandler();
|
||||
UserDetailsService users() {
|
||||
UserDetails user = User.builder()
|
||||
.username("admin")
|
||||
.password("{noop}123456")
|
||||
.roles("USER")
|
||||
.build();
|
||||
return new InMemoryUserDetailsManager(user);
|
||||
}
|
||||
|
||||
/**
|
||||
* SSO 退出逻辑处理
|
||||
* @return LogoutSuccessHandler
|
||||
*/
|
||||
@Bean
|
||||
public LogoutSuccessHandler logoutSuccessHandler() {
|
||||
return new SsoLogoutSuccessHandler();
|
||||
}
|
||||
|
||||
/**
|
||||
* 密码处理器
|
||||
* @return 动态密码处理器 {类型}密文
|
||||
*/
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
|
||||
}
|
||||
|
||||
}
|
||||
|
153
pig-auth/src/main/java/com/pig4cloud/pig/auth/endpoint/LoginEndpoint.java
Executable file
153
pig-auth/src/main/java/com/pig4cloud/pig/auth/endpoint/LoginEndpoint.java
Executable file
@ -0,0 +1,153 @@
|
||||
package com.pig4cloud.pig.auth.endpoint;
|
||||
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import com.pig4cloud.pig.common.core.constant.SecurityConstants;
|
||||
import com.pig4cloud.pig.common.security.service.PigUserDetailsService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.server.ServletServerHttpResponse;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.oauth2.core.*;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
|
||||
import org.springframework.security.oauth2.core.http.converter.OAuth2AccessTokenResponseHttpMessageConverter;
|
||||
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.client.RegisteredClient;
|
||||
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.OAuth2RefreshTokenGenerator;
|
||||
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 登录端点
|
||||
*
|
||||
* @author lengleng
|
||||
* @date 2022/5/27
|
||||
*/
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/password")
|
||||
public class LoginEndpoint {
|
||||
|
||||
private final OAuth2AuthorizationService tokenService;
|
||||
|
||||
private final RegisteredClientRepository registeredClientRepository;
|
||||
|
||||
private final OAuth2TokenGenerator tokenGenerator;
|
||||
|
||||
private final HttpMessageConverter<OAuth2AccessTokenResponse> accessTokenHttpResponseConverter = new OAuth2AccessTokenResponseHttpMessageConverter();
|
||||
|
||||
private final OAuth2RefreshTokenGenerator refreshTokenGenerator = new OAuth2RefreshTokenGenerator();
|
||||
|
||||
@SneakyThrows
|
||||
@RequestMapping("/login")
|
||||
public void login(HttpServletResponse response, HttpServletRequest request) {
|
||||
|
||||
RegisteredClient client = registeredClientRepository.findByClientId("pig");
|
||||
|
||||
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken("admin",
|
||||
"123");
|
||||
// @formatter:off
|
||||
DefaultOAuth2TokenContext.Builder builder = DefaultOAuth2TokenContext.builder()
|
||||
.registeredClient(client)
|
||||
.principal(authenticationToken)
|
||||
.tokenType(OAuth2TokenType.ACCESS_TOKEN)
|
||||
.authorizationGrantType(AuthorizationGrantType.PASSWORD);
|
||||
// @formatter:on
|
||||
OAuth2Token generatedAccessToken = this.tokenGenerator.generate(builder.build());
|
||||
OAuth2AccessToken accessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,
|
||||
generatedAccessToken.getTokenValue(), generatedAccessToken.getIssuedAt(),
|
||||
generatedAccessToken.getExpiresAt(), builder.build().getAuthorizedScopes());
|
||||
|
||||
// @formatter:off
|
||||
OAuth2Authorization.Builder authorizationBuilder = OAuth2Authorization.withRegisteredClient(client)
|
||||
.principalName("pig")
|
||||
.principalName(authenticationToken.getName())
|
||||
.authorizationGrantType(AuthorizationGrantType.PASSWORD);
|
||||
// @formatter:on
|
||||
if (generatedAccessToken instanceof ClaimAccessor) {
|
||||
authorizationBuilder.token(accessToken,
|
||||
(metadata) -> metadata.put(OAuth2Authorization.Token.CLAIMS_METADATA_NAME,
|
||||
((ClaimAccessor) generatedAccessToken).getClaims()));
|
||||
}
|
||||
else {
|
||||
authorizationBuilder.accessToken(accessToken);
|
||||
}
|
||||
|
||||
OAuth2Token generatedRefreshToken = this.refreshTokenGenerator
|
||||
.generate(builder.tokenType(OAuth2TokenType.REFRESH_TOKEN)
|
||||
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN).build());
|
||||
authorizationBuilder.refreshToken((OAuth2RefreshToken) generatedRefreshToken);
|
||||
OAuth2Authorization authorization = authorizationBuilder.build();
|
||||
tokenService.save(authorization);
|
||||
|
||||
Map<String, Object> additionalParameters = new HashMap<>();
|
||||
|
||||
additionalParameters.put("license", "pig");
|
||||
|
||||
Map<String, PigUserDetailsService> userDetailsServiceMap = SpringUtil
|
||||
.getBeansOfType(PigUserDetailsService.class);
|
||||
Optional<PigUserDetailsService> optional = userDetailsServiceMap.values().stream()
|
||||
.filter(service -> service.support(client.getClientId(), "password"))
|
||||
.max(Comparator.comparingInt(Ordered::getOrder));
|
||||
|
||||
UserDetails admin = optional.get().loadUserByUsername("admin");
|
||||
|
||||
additionalParameters.put(SecurityConstants.DETAILS_USER, admin);
|
||||
|
||||
OAuth2AccessTokenAuthenticationToken oAuth2AccessTokenAuthenticationToken = new OAuth2AccessTokenAuthenticationToken(
|
||||
client, authenticationToken, accessToken, (OAuth2RefreshToken) generatedRefreshToken,
|
||||
additionalParameters);
|
||||
sendAccessTokenResponse(request, response, oAuth2AccessTokenAuthenticationToken);
|
||||
|
||||
}
|
||||
|
||||
@GetMapping("/info")
|
||||
public OAuth2Authorization info(String token) {
|
||||
return tokenService.findByToken(token, OAuth2TokenType.ACCESS_TOKEN);
|
||||
}
|
||||
|
||||
private void sendAccessTokenResponse(HttpServletRequest request, HttpServletResponse response,
|
||||
Authentication authentication) throws IOException {
|
||||
|
||||
OAuth2AccessTokenAuthenticationToken accessTokenAuthentication = (OAuth2AccessTokenAuthenticationToken) authentication;
|
||||
|
||||
OAuth2AccessToken accessToken = accessTokenAuthentication.getAccessToken();
|
||||
OAuth2RefreshToken refreshToken = accessTokenAuthentication.getRefreshToken();
|
||||
Map<String, Object> additionalParameters = accessTokenAuthentication.getAdditionalParameters();
|
||||
|
||||
OAuth2AccessTokenResponse.Builder builder = OAuth2AccessTokenResponse.withToken(accessToken.getTokenValue())
|
||||
.tokenType(accessToken.getTokenType()).scopes(accessToken.getScopes());
|
||||
if (accessToken.getIssuedAt() != null && accessToken.getExpiresAt() != null) {
|
||||
builder.expiresIn(ChronoUnit.SECONDS.between(accessToken.getIssuedAt(), accessToken.getExpiresAt()));
|
||||
}
|
||||
if (refreshToken != null) {
|
||||
builder.refreshToken(refreshToken.getTokenValue());
|
||||
}
|
||||
if (!CollectionUtils.isEmpty(additionalParameters)) {
|
||||
builder.additionalParameters(additionalParameters);
|
||||
}
|
||||
OAuth2AccessTokenResponse accessTokenResponse = builder.build();
|
||||
ServletServerHttpResponse httpResponse = new ServletServerHttpResponse(response);
|
||||
this.accessTokenHttpResponseConverter.write(accessTokenResponse, null, httpResponse);
|
||||
}
|
||||
|
||||
}
|
@ -1,168 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2020 pig4cloud Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.pig4cloud.pig.auth.endpoint;
|
||||
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.pig4cloud.pig.common.core.constant.CacheConstants;
|
||||
import com.pig4cloud.pig.common.core.constant.CommonConstants;
|
||||
import com.pig4cloud.pig.common.core.util.R;
|
||||
import com.pig4cloud.pig.common.core.util.SpringContextHolder;
|
||||
import com.pig4cloud.pig.common.security.annotation.Inner;
|
||||
import com.pig4cloud.pig.common.security.util.SecurityUtils;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.security.authentication.event.LogoutSuccessEvent;
|
||||
import org.springframework.security.oauth2.common.OAuth2AccessToken;
|
||||
import org.springframework.security.oauth2.common.OAuth2RefreshToken;
|
||||
import org.springframework.security.oauth2.provider.AuthorizationRequest;
|
||||
import org.springframework.security.oauth2.provider.ClientDetails;
|
||||
import org.springframework.security.oauth2.provider.ClientDetailsService;
|
||||
import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
||||
import org.springframework.security.oauth2.provider.token.TokenStore;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author lengleng
|
||||
* @date 2019/2/1 删除token端点
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/token")
|
||||
public class PigTokenEndpoint {
|
||||
|
||||
private final ClientDetailsService clientDetailsService;
|
||||
|
||||
private final TokenStore tokenStore;
|
||||
|
||||
private final RedisTemplate redisTemplate;
|
||||
|
||||
private final CacheManager cacheManager;
|
||||
|
||||
/**
|
||||
* 认证页面
|
||||
* @param modelAndView
|
||||
* @param error 表单登录失败处理回调的错误信息
|
||||
* @return ModelAndView
|
||||
*/
|
||||
@GetMapping("/login")
|
||||
public ModelAndView require(ModelAndView modelAndView, @RequestParam(required = false) String error) {
|
||||
modelAndView.setViewName("ftl/login");
|
||||
modelAndView.addObject("error", error);
|
||||
return modelAndView;
|
||||
}
|
||||
|
||||
/**
|
||||
* 确认授权页面
|
||||
* @param request
|
||||
* @param session
|
||||
* @param modelAndView
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/confirm_access")
|
||||
public ModelAndView confirm(HttpServletRequest request, HttpSession session, ModelAndView modelAndView) {
|
||||
Map<String, Object> scopeList = (Map<String, Object>) request.getAttribute("scopes");
|
||||
modelAndView.addObject("scopeList", scopeList.keySet());
|
||||
|
||||
Object auth = session.getAttribute("authorizationRequest");
|
||||
if (auth != null) {
|
||||
AuthorizationRequest authorizationRequest = (AuthorizationRequest) auth;
|
||||
ClientDetails clientDetails = clientDetailsService.loadClientByClientId(authorizationRequest.getClientId());
|
||||
modelAndView.addObject("app", clientDetails.getAdditionalInformation());
|
||||
modelAndView.addObject("user", SecurityUtils.getUser());
|
||||
}
|
||||
|
||||
modelAndView.setViewName("ftl/confirm");
|
||||
return modelAndView;
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出并删除token
|
||||
* @param authHeader Authorization
|
||||
*/
|
||||
@DeleteMapping("/logout")
|
||||
public R<Boolean> logout(@RequestHeader(value = HttpHeaders.AUTHORIZATION, required = false) String authHeader) {
|
||||
if (StrUtil.isBlank(authHeader)) {
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
String tokenValue = authHeader.replace(OAuth2AccessToken.BEARER_TYPE, StrUtil.EMPTY).trim();
|
||||
return removeToken(tokenValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 令牌管理调用
|
||||
* @param token token
|
||||
*/
|
||||
@Inner
|
||||
@DeleteMapping("/{token}")
|
||||
public R<Boolean> removeToken(@PathVariable("token") String token) {
|
||||
OAuth2AccessToken accessToken = tokenStore.readAccessToken(token);
|
||||
if (accessToken == null || StrUtil.isBlank(accessToken.getValue())) {
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
OAuth2Authentication auth2Authentication = tokenStore.readAuthentication(accessToken);
|
||||
// 清空用户信息
|
||||
cacheManager.getCache(CacheConstants.USER_DETAILS).evict(auth2Authentication.getName());
|
||||
|
||||
// 清空access token
|
||||
tokenStore.removeAccessToken(accessToken);
|
||||
|
||||
// 清空 refresh token
|
||||
OAuth2RefreshToken refreshToken = accessToken.getRefreshToken();
|
||||
tokenStore.removeRefreshToken(refreshToken);
|
||||
|
||||
// 处理自定义退出事件,保存相关日志
|
||||
SpringContextHolder.publishEvent(new LogoutSuccessEvent(auth2Authentication));
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询token
|
||||
* @param params 分页参数
|
||||
* @return
|
||||
*/
|
||||
@Inner
|
||||
@PostMapping("/page")
|
||||
public R<Page> tokenList(@RequestBody Map<String, Object> params) {
|
||||
// 根据分页参数获取对应数据
|
||||
String key = String.format("%sauth_to_access:*", CacheConstants.PROJECT_OAUTH_ACCESS);
|
||||
int current = MapUtil.getInt(params, CommonConstants.CURRENT);
|
||||
int size = MapUtil.getInt(params, CommonConstants.SIZE);
|
||||
Set<String> keys = redisTemplate.keys(key);
|
||||
List<String> pages = keys.stream().skip((current - 1) * size).limit(size).collect(Collectors.toList());
|
||||
Page result = new Page(current, size);
|
||||
result.setRecords(redisTemplate.opsForValue().multiGet(pages));
|
||||
result.setTotal(keys.size());
|
||||
return R.ok(result);
|
||||
}
|
||||
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2020 pig4cloud Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.pig4cloud.pig.auth.handler;
|
||||
|
||||
import com.pig4cloud.pig.admin.api.entity.SysLog;
|
||||
import com.pig4cloud.pig.common.core.util.SpringContextHolder;
|
||||
import com.pig4cloud.pig.common.log.event.SysLogEvent;
|
||||
import com.pig4cloud.pig.common.log.util.LogTypeEnum;
|
||||
import com.pig4cloud.pig.common.log.util.SysLogUtils;
|
||||
import com.pig4cloud.pig.common.security.handler.AbstractAuthenticationFailureEventHandler;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author lengleng
|
||||
* @date 2019/2/1
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class PigAuthenticationFailureEventHandler extends AbstractAuthenticationFailureEventHandler {
|
||||
|
||||
/**
|
||||
* 处理登录失败方法
|
||||
* <p>
|
||||
* @param authenticationException 登录的authentication 对象
|
||||
* @param authentication 登录的authenticationException 对象
|
||||
*/
|
||||
@Override
|
||||
public void handle(AuthenticationException authenticationException, Authentication authentication) {
|
||||
log.info("用户:{} 登录失败,异常:{}", authentication.getPrincipal(), authenticationException.getLocalizedMessage());
|
||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
SysLog logVo = SysLogUtils.getSysLog();
|
||||
logVo.setTitle("登录失败");
|
||||
logVo.setType(LogTypeEnum.ERROR.getType());
|
||||
logVo.setException(authenticationException.getMessage());
|
||||
// 发送异步日志事件
|
||||
Long startTime = System.currentTimeMillis();
|
||||
Long endTime = System.currentTimeMillis();
|
||||
logVo.setTime(endTime - startTime);
|
||||
logVo.setCreateBy(authentication.getName());
|
||||
logVo.setUpdateBy(authentication.getName());
|
||||
SpringContextHolder.publishEvent(new SysLogEvent(logVo));
|
||||
}
|
||||
|
||||
}
|
@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2020 pig4cloud Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.pig4cloud.pig.auth.handler;
|
||||
|
||||
import com.pig4cloud.pig.admin.api.entity.SysLog;
|
||||
import com.pig4cloud.pig.common.core.util.SpringContextHolder;
|
||||
import com.pig4cloud.pig.common.log.event.SysLogEvent;
|
||||
import com.pig4cloud.pig.common.log.util.SysLogUtils;
|
||||
import com.pig4cloud.pig.common.security.handler.AbstractAuthenticationSuccessEventHandler;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author lengleng
|
||||
* @date 2019/2/1
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class PigAuthenticationSuccessEventHandler extends AbstractAuthenticationSuccessEventHandler {
|
||||
|
||||
/**
|
||||
* 处理登录成功方法
|
||||
* <p>
|
||||
* 获取到登录的authentication 对象
|
||||
* @param authentication 登录对象
|
||||
*/
|
||||
@Override
|
||||
public void handle(Authentication authentication) {
|
||||
log.info("用户:{} 登录成功", authentication.getPrincipal());
|
||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
SysLog logVo = SysLogUtils.getSysLog();
|
||||
logVo.setTitle("登录成功");
|
||||
// 发送异步日志事件
|
||||
Long startTime = System.currentTimeMillis();
|
||||
Long endTime = System.currentTimeMillis();
|
||||
logVo.setTime(endTime - startTime);
|
||||
logVo.setCreateBy(authentication.getName());
|
||||
logVo.setUpdateBy(authentication.getName());
|
||||
SpringContextHolder.publishEvent(new SysLogEvent(logVo));
|
||||
}
|
||||
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2020 pig4cloud Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.pig4cloud.pig.auth.handler;
|
||||
|
||||
import com.pig4cloud.pig.admin.api.entity.SysLog;
|
||||
import com.pig4cloud.pig.common.core.util.SpringContextHolder;
|
||||
import com.pig4cloud.pig.common.core.util.WebUtils;
|
||||
import com.pig4cloud.pig.common.log.event.SysLogEvent;
|
||||
import com.pig4cloud.pig.common.log.util.SysLogUtils;
|
||||
import com.pig4cloud.pig.common.security.handler.AbstractLogoutSuccessEventHandler;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author zhangran
|
||||
* @date 2021/6/23
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class PigLogoutSuccessEventHandler extends AbstractLogoutSuccessEventHandler {
|
||||
|
||||
/**
|
||||
* 处理退出成功方法
|
||||
* <p>
|
||||
* 获取到登录的authentication 对象
|
||||
* @param authentication 登录对象
|
||||
*/
|
||||
@Override
|
||||
public void handle(Authentication authentication) {
|
||||
log.info("用户:{} 退出成功", authentication.getPrincipal());
|
||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
|
||||
SysLog logVo = SysLogUtils.getSysLog();
|
||||
logVo.setTitle("退出成功");
|
||||
// 发送异步日志事件
|
||||
Long startTime = System.currentTimeMillis();
|
||||
Long endTime = System.currentTimeMillis();
|
||||
logVo.setTime(endTime - startTime);
|
||||
|
||||
// 设置对应的token
|
||||
WebUtils.getRequest().ifPresent(request -> logVo.setParams(request.getHeader(HttpHeaders.AUTHORIZATION)));
|
||||
|
||||
// 这边设置ServiceId
|
||||
if (authentication instanceof OAuth2Authentication) {
|
||||
OAuth2Authentication auth2Authentication = (OAuth2Authentication) authentication;
|
||||
logVo.setServiceId(auth2Authentication.getOAuth2Request().getClientId());
|
||||
}
|
||||
logVo.setCreateBy(authentication.getName());
|
||||
logVo.setUpdateBy(authentication.getName());
|
||||
SpringContextHolder.publishEvent(new SysLogEvent(logVo));
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user