mirror of
https://gitee.com/log4j/pig.git
synced 2024-12-22 12:48:58 +08:00
✨ Introducing new features. 支持授权码模式
This commit is contained in:
parent
30852ce488
commit
b20f476371
@ -27,16 +27,15 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configurers.oauth2.server.authorization.OAuth2AuthorizationServerConfigurer;
|
||||
import org.springframework.security.oauth2.server.authorization.InMemoryOAuth2AuthorizationConsentService;
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
|
||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationCodeRequestAuthenticationProvider;
|
||||
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.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.oauth2.server.authorization.web.authentication.*;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
|
||||
@ -51,7 +50,7 @@ import java.util.Arrays;
|
||||
@Configuration
|
||||
public class AuthorizationServerConfiguration {
|
||||
|
||||
private static final String CUSTOM_CONSENT_PAGE_URI = "/oauth2/login";
|
||||
private static final String CUSTOM_CONSENT_PAGE_URI = "/token/confirm_access";
|
||||
|
||||
/**
|
||||
* 定义 Spring Security 的拦截器链,比如我们的 授权url、获取token的url 需要由那个过滤器来处理,此处配置这个。
|
||||
@ -68,6 +67,7 @@ public class AuthorizationServerConfiguration {
|
||||
http.apply(authorizationServerConfigurer.tokenEndpoint(
|
||||
(tokenEndpoint) -> tokenEndpoint.accessTokenRequestConverter(new DelegatingAuthenticationConverter(
|
||||
Arrays.asList(new OAuth2AuthorizationCodeAuthenticationConverter(),
|
||||
new OAuth2AuthorizationCodeRequestAuthenticationConverter(),
|
||||
new OAuth2RefreshTokenAuthenticationConverter(),
|
||||
new OAuth2ClientCredentialsAuthenticationConverter(),
|
||||
new OAuth2ResourceOwnerPasswordAuthenticationConverter())))));
|
||||
@ -82,7 +82,9 @@ public class AuthorizationServerConfiguration {
|
||||
.authorizeRequests(authorizeRequests -> authorizeRequests.anyRequest().authenticated())
|
||||
.csrf(csrf -> csrf.ignoringRequestMatchers(endpointsMatcher)).apply(authorizationServerConfigurer);
|
||||
|
||||
SecurityFilterChain securityFilterChain = http.formLogin(Customizer.withDefaults()).build();
|
||||
// SAS 统一认证调整至登录页面
|
||||
SecurityFilterChain securityFilterChain = http.csrf().disable()
|
||||
.formLogin(loginConfigurer -> loginConfigurer.loginPage("/token/login")).build();
|
||||
|
||||
addCustomOAuth2PasswordAuthenticationProvider(http);
|
||||
return securityFilterChain;
|
||||
@ -144,6 +146,11 @@ public class AuthorizationServerConfiguration {
|
||||
// 处理 OAuth2ResourceOwnerPasswordAuthenticationToken
|
||||
http.authenticationProvider(resourceOwnerPasswordAuthenticationProvider);
|
||||
|
||||
//
|
||||
RegisteredClientRepository clientRepository = http.getSharedObject(RegisteredClientRepository.class);
|
||||
http.authenticationProvider(new OAuth2AuthorizationCodeRequestAuthenticationProvider(clientRepository,
|
||||
authorizationService, new InMemoryOAuth2AuthorizationConsentService()));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -16,11 +16,16 @@
|
||||
|
||||
package com.pig4cloud.pig.auth.config;
|
||||
|
||||
import com.pig4cloud.pig.common.security.component.PigDaoAuthenticationProvider;
|
||||
import com.pig4cloud.pig.common.security.handler.FormAuthenticationFailureHandler;
|
||||
import com.pig4cloud.pig.common.security.handler.SsoLogoutSuccessHandler;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
|
||||
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
|
||||
|
||||
/**
|
||||
* 服务安全相关配置
|
||||
@ -28,7 +33,7 @@ import org.springframework.security.web.SecurityFilterChain;
|
||||
* @author lengleng
|
||||
* @date 2022/1/12
|
||||
*/
|
||||
@EnableWebSecurity
|
||||
@EnableWebSecurity(debug = true)
|
||||
public class WebSecurityConfiguration {
|
||||
|
||||
/**
|
||||
@ -42,11 +47,40 @@ public class WebSecurityConfiguration {
|
||||
http.authorizeRequests(
|
||||
// 暴露自定义 的 password 等端点
|
||||
authorizeRequests -> authorizeRequests.antMatchers("/token/*").permitAll().anyRequest().authenticated())
|
||||
// 禁止 csrf
|
||||
.csrf().disable()
|
||||
// 个性化 formLogin
|
||||
.csrf().disable().formLogin(Customizer.withDefaults());
|
||||
.formLogin().loginPage("/token/login").loginProcessingUrl("/token/form")
|
||||
.failureHandler(authenticationFailureHandler()).and().logout()
|
||||
.logoutSuccessHandler(logoutSuccessHandler()).deleteCookies("JSESSIONID").invalidateHttpSession(true);
|
||||
|
||||
// 处理 UsernamePasswordAuthenticationToken
|
||||
http.authenticationProvider(new PigDaoAuthenticationProvider());
|
||||
|
||||
// http.authenticationProvider(new PigDaoAuthenticationProvider());
|
||||
return http.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public WebSecurityCustomizer webSecurityCustomizer() {
|
||||
return (web) -> web.ignoring().antMatchers("/css/**", "/error");
|
||||
}
|
||||
|
||||
/**
|
||||
* sso 表单登录失败处理
|
||||
* @return FormAuthenticationFailureHandler
|
||||
*/
|
||||
@Bean
|
||||
public AuthenticationFailureHandler authenticationFailureHandler() {
|
||||
return new FormAuthenticationFailureHandler();
|
||||
}
|
||||
|
||||
/**
|
||||
* SSO 退出逻辑处理
|
||||
* @return LogoutSuccessHandler
|
||||
*/
|
||||
@Bean
|
||||
public LogoutSuccessHandler logoutSuccessHandler() {
|
||||
return new SsoLogoutSuccessHandler();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -19,11 +19,13 @@ 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.admin.api.entity.SysOauthClientDetails;
|
||||
import com.pig4cloud.pig.admin.api.feign.RemoteClientDetailsService;
|
||||
import com.pig4cloud.pig.auth.support.OAuth2EndpointUtils;
|
||||
import com.pig4cloud.pig.auth.support.OAuth2ErrorCodesExpand;
|
||||
import com.pig4cloud.pig.common.core.constant.CacheConstants;
|
||||
import com.pig4cloud.pig.common.core.constant.CommonConstants;
|
||||
import com.pig4cloud.pig.common.core.constant.SecurityConstants;
|
||||
import com.pig4cloud.pig.common.core.util.R;
|
||||
import com.pig4cloud.pig.common.core.util.SpringContextHolder;
|
||||
import com.pig4cloud.pig.common.security.annotation.Inner;
|
||||
@ -44,16 +46,17 @@ import org.springframework.security.oauth2.core.OAuth2AccessToken;
|
||||
import org.springframework.security.oauth2.core.OAuth2Error;
|
||||
import org.springframework.security.oauth2.core.OAuth2TokenType;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||
import org.springframework.security.oauth2.core.http.converter.OAuth2AccessTokenResponseHttpMessageConverter;
|
||||
import org.springframework.security.oauth2.core.http.converter.OAuth2ErrorHttpMessageConverter;
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.security.Principal;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@ -75,7 +78,7 @@ public class PigTokenEndpoint {
|
||||
|
||||
private final OAuth2AuthorizationService authorizationService;
|
||||
|
||||
private RemoteClientDetailsService clientDetailsService;
|
||||
private final RemoteClientDetailsService clientDetailsService;
|
||||
|
||||
private final RedisTemplate redisTemplate;
|
||||
|
||||
@ -94,28 +97,19 @@ public class PigTokenEndpoint {
|
||||
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());
|
||||
}
|
||||
public ModelAndView confirm(Principal principal, ModelAndView modelAndView,
|
||||
@RequestParam(OAuth2ParameterNames.CLIENT_ID) String clientId,
|
||||
@RequestParam(OAuth2ParameterNames.SCOPE) String scope,
|
||||
@RequestParam(OAuth2ParameterNames.STATE) String state) {
|
||||
|
||||
R<SysOauthClientDetails> r = clientDetailsService.getClientDetailsById(clientId, SecurityConstants.FROM_IN);
|
||||
SysOauthClientDetails clientDetails = r.getData();
|
||||
Set<String> authorizedScopes = StringUtils.commaDelimitedListToSet(clientDetails.getScope());
|
||||
modelAndView.addObject("clientId", clientId);
|
||||
modelAndView.addObject("state", state);
|
||||
modelAndView.addObject("scopeList", authorizedScopes);
|
||||
modelAndView.addObject("principalName", principal.getName());
|
||||
modelAndView.setViewName("ftl/confirm");
|
||||
return modelAndView;
|
||||
}
|
||||
@ -159,7 +153,6 @@ public class PigTokenEndpoint {
|
||||
|
||||
OAuth2AccessTokenResponse sendAccessTokenResponse = OAuth2EndpointUtils.sendAccessTokenResponse(authorization);
|
||||
this.accessTokenHttpResponseConverter.write(sendAccessTokenResponse, MediaType.APPLICATION_JSON, httpResponse);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2,50 +2,55 @@
|
||||
<html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="viewport"
|
||||
content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"/>
|
||||
<title>Pig 第三方授权</title>
|
||||
<link rel="stylesheet" type="text/css" href="/css/bootstrap.min.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="/css/signin.css"/>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="viewport"
|
||||
content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"/>
|
||||
<title>Pig 第三方授权</title>
|
||||
<link rel="stylesheet" type="text/css" href="/css/bootstrap.min.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="/css/signin.css"/>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<nav class="navbar navbar-default container-fluid">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<a class="navbar-brand" href="#">开放平台</a>
|
||||
</div>
|
||||
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-5">
|
||||
<p class="navbar-text navbar-right">
|
||||
<a target="_blank" href="https://pig4cloud.com">技术支持</a>
|
||||
</p>
|
||||
<p class="navbar-text navbar-right">
|
||||
<a target="_blank" href="https://pig4cloud.com">${user.username}</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<a class="navbar-brand" href="#">开放平台</a>
|
||||
</div>
|
||||
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-5">
|
||||
<p class="navbar-text navbar-right">
|
||||
<a target="_blank" href="https://pig4cloud.com">技术支持</a>
|
||||
</p>
|
||||
<p class="navbar-text navbar-right">
|
||||
<#if principalName=="anonymousUser">
|
||||
未登录
|
||||
<#else>
|
||||
<a target="_blank" href="https://pig4cloud.com">${principalName}</a>
|
||||
</#if>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<div style="padding-top: 80px;width: 300px; color: #555; margin:0px auto;">
|
||||
<form id='confirmationForm' name='confirmationForm' action="/oauth/authorize" method='post'>
|
||||
<input name='user_oauth_approval' value='true' type='hidden'/>
|
||||
<p>
|
||||
<a href="${app.website!''}" target="_blank">${app.appName!'未定义应用名称'}</a> 将获得以下权限:</p>
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item"> <span>
|
||||
<form id='confirmationForm' name='confirmationForm' action="/oauth2/authorize" method='post'>
|
||||
<input type="hidden" name="client_id" value="${clientId}">
|
||||
<input type="hidden" name="state" value="${state}">
|
||||
|
||||
<p>
|
||||
将获得以下权限:</p>
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item"> <span>
|
||||
<#list scopeList as scope>
|
||||
<input type="hidden" name="${scope}" value="true"/>
|
||||
<input type="checkbox" disabled checked="checked"/><label>${scope}</label>
|
||||
<input type="checkbox" checked="checked" name="scope" value="${scope}"/><label>${scope}</label>
|
||||
</#list>
|
||||
</ul>
|
||||
<p class="help-block">授权后表明你已同意 <a>服务协议</a></p>
|
||||
<button class="btn btn-success pull-right" type="submit" id="write-email-btn">授权</button>
|
||||
</p>
|
||||
</form>
|
||||
</ul>
|
||||
<p class="help-block">授权后表明你已同意 <a>服务协议</a></p>
|
||||
<button class="btn btn-success pull-right" type="submit" id="write-email-btn">授权</button>
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
<footer>
|
||||
<p>support by: pig4cloud.com</p>
|
||||
<p>email: <a href="mailto:wangiegie@gmail.com">wangiegie@gmail.com</a>.</p>
|
||||
<p>support by: pig4cloud.com</p>
|
||||
<p>email: <a href="mailto:wangiegie@gmail.com">wangiegie@gmail.com</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -31,7 +31,7 @@ public class SsoLogoutSuccessHandler implements LogoutSuccessHandler {
|
||||
if (StrUtil.isNotBlank(redirectUrl)) {
|
||||
response.sendRedirect(redirectUrl);
|
||||
}
|
||||
else {
|
||||
else if (StrUtil.isNotBlank(request.getHeader(HttpHeaders.REFERER))) {
|
||||
// 默认跳转referer 地址
|
||||
String referer = request.getHeader(HttpHeaders.REFERER);
|
||||
response.sendRedirect(referer);
|
||||
|
@ -2,7 +2,6 @@ package com.pig4cloud.pig.common.security.service;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.security.oauth2.core.OAuth2AccessToken;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthorizationCode;
|
||||
@ -19,7 +18,7 @@ import org.springframework.util.Assert;
|
||||
@RequiredArgsConstructor
|
||||
public class PigRedisOAuth2AuthorizationService implements OAuth2AuthorizationService {
|
||||
|
||||
private static final String AUTHORIZATION = HttpHeaders.AUTHORIZATION;
|
||||
private static final String AUTHORIZATION = "token";
|
||||
|
||||
private final RedisTemplate<String, String> redisTemplate;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user