mirror of
https://gitee.com/log4j/pig.git
synced 2024-12-22 12:48:58 +08:00
♻️ Refactoring code. 重构认证中心代码 简易代码实现
This commit is contained in:
parent
dc0931af40
commit
856c4e645e
@ -18,6 +18,7 @@ package com.pig4cloud.pig.auth.config;
|
||||
|
||||
import com.pig4cloud.pig.auth.support.CustomeOAuth2AccessTokenGenerator;
|
||||
import com.pig4cloud.pig.auth.support.core.CustomeOAuth2TokenCustomizer;
|
||||
import com.pig4cloud.pig.auth.support.core.FormIdentityLoginConfigurer;
|
||||
import com.pig4cloud.pig.auth.support.core.PigDaoAuthenticationProvider;
|
||||
import com.pig4cloud.pig.auth.support.handler.PigAuthenticationFailureEventHandler;
|
||||
import com.pig4cloud.pig.auth.support.handler.PigAuthenticationSuccessEventHandler;
|
||||
@ -43,6 +44,7 @@ import org.springframework.security.oauth2.server.authorization.web.authenticati
|
||||
import org.springframework.security.web.DefaultSecurityFilterChain;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.authentication.AuthenticationConverter;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@ -70,13 +72,12 @@ public class AuthorizationServerConfiguration {
|
||||
}).authorizationEndpoint( // 授权码端点个性化confirm页面
|
||||
authorizationEndpoint -> authorizationEndpoint.consentPage(SecurityConstants.CUSTOM_CONSENT_PAGE_URI)));
|
||||
|
||||
DefaultSecurityFilterChain securityFilterChain = http
|
||||
.requestMatcher(authorizationServerConfigurer.getEndpointsMatcher())
|
||||
.authorizeRequests(authorizeRequests -> authorizeRequests.anyRequest().authenticated())// 授权端点开启安全认证
|
||||
RequestMatcher endpointsMatcher = authorizationServerConfigurer.getEndpointsMatcher();
|
||||
DefaultSecurityFilterChain securityFilterChain = http.requestMatcher(endpointsMatcher)
|
||||
.authorizeRequests(authorizeRequests -> authorizeRequests.anyRequest().authenticated())
|
||||
.apply(authorizationServerConfigurer.authorizationService(authorizationService)// redis存储token的实现
|
||||
.providerSettings(ProviderSettings.builder().issuer(SecurityConstants.PROJECT_LICENSE).build()))
|
||||
.and()// SAS 统一认证调整至登录页面
|
||||
.formLogin(loginConfigurer -> loginConfigurer.loginPage("/token/login")).csrf().disable().build();
|
||||
.and().apply(new FormIdentityLoginConfigurer()).and().build();
|
||||
|
||||
// 注入自定义授权模式实现
|
||||
addCustomOAuth2GrantAuthenticationProvider(http);
|
||||
|
@ -16,9 +16,8 @@
|
||||
|
||||
package com.pig4cloud.pig.auth.config;
|
||||
|
||||
import com.pig4cloud.pig.auth.support.core.FormIdentityLoginConfigurer;
|
||||
import com.pig4cloud.pig.auth.support.core.PigDaoAuthenticationProvider;
|
||||
import com.pig4cloud.pig.auth.support.handler.FormAuthenticationFailureHandler;
|
||||
import com.pig4cloud.pig.auth.support.handler.SsoLogoutSuccessHandler;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
@ -42,19 +41,9 @@ public class WebSecurityConfiguration {
|
||||
*/
|
||||
@Bean
|
||||
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
|
||||
http.authorizeRequests(
|
||||
// 暴露自定义 的 password 等端点
|
||||
authorizeRequests -> authorizeRequests.antMatchers("/token/*").permitAll().anyRequest().authenticated())
|
||||
// 个性化 formLogin
|
||||
.formLogin().loginPage("/token/login").loginProcessingUrl("/token/form")
|
||||
// SSO登录失败处理
|
||||
.failureHandler(new FormAuthenticationFailureHandler()).and().logout()
|
||||
// SSO登出成功处理
|
||||
.logoutSuccessHandler(new SsoLogoutSuccessHandler()).deleteCookies("JSESSIONID")
|
||||
.invalidateHttpSession(true)
|
||||
// 禁止 login form csrf
|
||||
.and().csrf().disable();
|
||||
|
||||
http.authorizeRequests(authorizeRequests -> authorizeRequests.antMatchers("/token/*").permitAll()// 开放自定义的部分端点
|
||||
.anyRequest().authenticated()).headers().frameOptions().sameOrigin()// 避免iframe同源无法登录
|
||||
.and().apply(new FormIdentityLoginConfigurer()); // 注入form login
|
||||
// 处理 UsernamePasswordAuthenticationToken
|
||||
http.authenticationProvider(new PigDaoAuthenticationProvider());
|
||||
return http.build();
|
||||
|
@ -0,0 +1,29 @@
|
||||
package com.pig4cloud.pig.auth.support.core;
|
||||
|
||||
import com.pig4cloud.pig.auth.support.handler.FormAuthenticationFailureHandler;
|
||||
import com.pig4cloud.pig.auth.support.handler.SsoLogoutSuccessHandler;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||
|
||||
/**
|
||||
* @author lengleng
|
||||
* @data 2022-06-04
|
||||
*
|
||||
* 基于授权码模式 统一认证登录 spring security & sas 都可以使用 所以抽取成 HttpConfigurer
|
||||
*/
|
||||
public final class FormIdentityLoginConfigurer
|
||||
extends AbstractHttpConfigurer<FormIdentityLoginConfigurer, HttpSecurity> {
|
||||
|
||||
@Override
|
||||
public void init(HttpSecurity http) throws Exception {
|
||||
http.formLogin(formLogin -> {
|
||||
formLogin.loginPage("/token/login");
|
||||
formLogin.loginProcessingUrl("/token/form");
|
||||
formLogin.failureHandler(new FormAuthenticationFailureHandler());
|
||||
|
||||
}).logout() // SSO登出成功处理
|
||||
.logoutSuccessHandler(new SsoLogoutSuccessHandler()).deleteCookies("JSESSIONID")
|
||||
.invalidateHttpSession(true).and().csrf().disable();
|
||||
}
|
||||
|
||||
}
|
@ -1,10 +1,12 @@
|
||||
package com.pig4cloud.pig.auth.support.core;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.extra.servlet.ServletUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import com.pig4cloud.pig.common.core.constant.SecurityConstants;
|
||||
import com.pig4cloud.pig.common.core.util.WebUtils;
|
||||
import com.pig4cloud.pig.common.security.service.PigUserDetailsService;
|
||||
import lombok.SneakyThrows;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.authentication.InternalAuthenticationServiceException;
|
||||
@ -12,7 +14,6 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticatio
|
||||
import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsPasswordService;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
@ -20,12 +21,14 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken;
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationConverter;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Comparator;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* @author lengleng
|
||||
@ -39,6 +42,8 @@ public class PigDaoAuthenticationProvider extends AbstractUserDetailsAuthenticat
|
||||
*/
|
||||
private static final String USER_NOT_FOUND_PASSWORD = "userNotFoundPassword";
|
||||
|
||||
private final static BasicAuthenticationConverter basicConvert = new BasicAuthenticationConverter();
|
||||
|
||||
private PasswordEncoder passwordEncoder;
|
||||
|
||||
/**
|
||||
@ -82,29 +87,29 @@ public class PigDaoAuthenticationProvider extends AbstractUserDetailsAuthenticat
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)
|
||||
throws AuthenticationException {
|
||||
|
||||
protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) {
|
||||
prepareTimingAttackProtection();
|
||||
HttpServletRequest request = WebUtils.getRequest().orElseThrow(
|
||||
(Supplier<Throwable>) () -> new InternalAuthenticationServiceException("web request is empty"));
|
||||
|
||||
// 此处已获得 客户端认证 获取对应 userDetailsService
|
||||
OAuth2ClientAuthenticationToken clientAuthentication = (OAuth2ClientAuthenticationToken) SecurityContextHolder
|
||||
.getContext().getAuthentication();
|
||||
Map<String, String> paramMap = ServletUtil.getParamMap(request);
|
||||
String grantType = paramMap.get(OAuth2ParameterNames.GRANT_TYPE);
|
||||
String clientId = paramMap.get(OAuth2ParameterNames.CLIENT_ID);
|
||||
|
||||
// SSO NPE 处理
|
||||
String clientId;
|
||||
if (clientAuthentication == null) {
|
||||
clientId = WebUtils.getRequest().get().getParameter("clientId");
|
||||
}
|
||||
else {
|
||||
clientId = clientAuthentication.getName();
|
||||
if (StrUtil.isBlank(clientId)) {
|
||||
clientId = basicConvert.convert(request).getName();
|
||||
}
|
||||
|
||||
Map<String, PigUserDetailsService> userDetailsServiceMap = SpringUtil
|
||||
.getBeansOfType(PigUserDetailsService.class);
|
||||
|
||||
String finalClientId = clientId;
|
||||
Optional<PigUserDetailsService> optional = userDetailsServiceMap.values().stream()
|
||||
.filter(service -> service.support(clientId, null)).max(Comparator.comparingInt(Ordered::getOrder));
|
||||
.filter(service -> service.support(finalClientId, grantType))
|
||||
.max(Comparator.comparingInt(Ordered::getOrder));
|
||||
|
||||
if (!optional.isPresent()) {
|
||||
throw new InternalAuthenticationServiceException("UserDetailsService error , not register");
|
||||
|
@ -98,6 +98,9 @@ public class PigAuthenticationSuccessEventHandler implements AuthenticationSucce
|
||||
}
|
||||
OAuth2AccessTokenResponse accessTokenResponse = builder.build();
|
||||
ServletServerHttpResponse httpResponse = new ServletServerHttpResponse(response);
|
||||
|
||||
// 无状态 注意删除 context 上下文的信息
|
||||
SecurityContextHolder.clearContext();
|
||||
this.accessTokenHttpResponseConverter.write(accessTokenResponse, null, httpResponse);
|
||||
}
|
||||
|
||||
|
@ -1,35 +1,36 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="">
|
||||
|
||||
<title>Pig 微服务统一认证</title>
|
||||
<title>Pig 微服务统一认证</title>
|
||||
|
||||
<link href="/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="/css/signin.css" rel="stylesheet">
|
||||
<link href="/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="/css/signin.css" rel="stylesheet">
|
||||
</head>
|
||||
|
||||
<body class="sign_body">
|
||||
<div class="container form-margin-top">
|
||||
<form class="form-signin" action="/token/form" method="post">
|
||||
<h2 class="form-signin-heading" align="center">统一认证系统</h2>
|
||||
<input type="hidden" name="clientId" class="form-control" value="pig" placeholder="所属客户端" >
|
||||
<input type="text" name="username" class="form-control form-margin-top" placeholder="账号" required autofocus>
|
||||
<input type="password" name="password" class="form-control" placeholder="密码" required>
|
||||
<button class="btn btn-lg btn-primary btn-block" type="submit">sign in</button>
|
||||
<form class="form-signin" action="/token/form" method="post">
|
||||
<h2 class="form-signin-heading" align="center">统一认证系统</h2>
|
||||
<input type="hidden" name="client_id" class="form-control" value="pig" placeholder="所属客户端">
|
||||
<input type="hidden" name="grant_type" class="form-control" value="password" placeholder="所属客户端">
|
||||
<input type="text" name="username" class="form-control form-margin-top" placeholder="账号" required autofocus>
|
||||
<input type="password" name="password" class="form-control" placeholder="密码" required>
|
||||
<button class="btn btn-lg btn-primary btn-block" type="submit">sign in</button>
|
||||
<#if error??>
|
||||
<span style="color: red; ">${error}</span>
|
||||
<span style="color: red; ">${error}</span>
|
||||
</#if>
|
||||
</form>
|
||||
</form>
|
||||
</div>
|
||||
<footer>
|
||||
<p>support by: pig4cloud</p>
|
||||
<p>email: <a href="mailto:pig4cloud@qq.com">pig4cloud@qq.com</a>.</p>
|
||||
<p>support by: pig4cloud</p>
|
||||
<p>email: <a href="mailto:pig4cloud@qq.com">pig4cloud@qq.com</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
Loading…
Reference in New Issue
Block a user