From b20f4763718dc03e1abec6c48798821202a59c5e Mon Sep 17 00:00:00 2001 From: lbw Date: Mon, 30 May 2022 22:49:27 +0800 Subject: [PATCH] =?UTF-8?q?:sparkles:=20Introducing=20new=20features.=20?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=8E=88=E6=9D=83=E7=A0=81=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AuthorizationServerConfiguration.java | 21 ++++-- .../auth/config/WebSecurityConfiguration.java | 42 ++++++++++- .../pig/auth/endpoint/PigTokenEndpoint.java | 41 +++++------ .../main/resources/templates/ftl/confirm.ftl | 73 ++++++++++--------- .../handler/SsoLogoutSuccessHandler.java | 2 +- .../PigRedisOAuth2AuthorizationService.java | 3 +- 6 files changed, 110 insertions(+), 72 deletions(-) diff --git a/pig-auth/src/main/java/com/pig4cloud/pig/auth/config/AuthorizationServerConfiguration.java b/pig-auth/src/main/java/com/pig4cloud/pig/auth/config/AuthorizationServerConfiguration.java index 5c755f11..f5713b41 100755 --- a/pig-auth/src/main/java/com/pig4cloud/pig/auth/config/AuthorizationServerConfiguration.java +++ b/pig-auth/src/main/java/com/pig4cloud/pig/auth/config/AuthorizationServerConfiguration.java @@ -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())); + } } diff --git a/pig-auth/src/main/java/com/pig4cloud/pig/auth/config/WebSecurityConfiguration.java b/pig-auth/src/main/java/com/pig4cloud/pig/auth/config/WebSecurityConfiguration.java index 522b6471..9f621027 100755 --- a/pig-auth/src/main/java/com/pig4cloud/pig/auth/config/WebSecurityConfiguration.java +++ b/pig-auth/src/main/java/com/pig4cloud/pig/auth/config/WebSecurityConfiguration.java @@ -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(); + } + } diff --git a/pig-auth/src/main/java/com/pig4cloud/pig/auth/endpoint/PigTokenEndpoint.java b/pig-auth/src/main/java/com/pig4cloud/pig/auth/endpoint/PigTokenEndpoint.java index 0bff60e4..eb8bd3f4 100644 --- a/pig-auth/src/main/java/com/pig4cloud/pig/auth/endpoint/PigTokenEndpoint.java +++ b/pig-auth/src/main/java/com/pig4cloud/pig/auth/endpoint/PigTokenEndpoint.java @@ -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 scopeList = (Map) 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 r = clientDetailsService.getClientDetailsById(clientId, SecurityConstants.FROM_IN); + SysOauthClientDetails clientDetails = r.getData(); + Set 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; } /** diff --git a/pig-auth/src/main/resources/templates/ftl/confirm.ftl b/pig-auth/src/main/resources/templates/ftl/confirm.ftl index 043111ae..92b503dc 100644 --- a/pig-auth/src/main/resources/templates/ftl/confirm.ftl +++ b/pig-auth/src/main/resources/templates/ftl/confirm.ftl @@ -2,50 +2,55 @@ - - - Pig 第三方授权 - - + + + Pig 第三方授权 + +
-
- -

- ${app.appName!'未定义应用名称'} 将获得以下权限:

-
    -
  • + + + + +

    + 将获得以下权限:

    +
      +
    • <#list scopeList as scope> - - + -
    -

    授权后表明你已同意 服务协议

    - -

    - +
+

授权后表明你已同意 服务协议

+ +

+
diff --git a/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/handler/SsoLogoutSuccessHandler.java b/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/handler/SsoLogoutSuccessHandler.java index af235f7a..66b9df67 100644 --- a/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/handler/SsoLogoutSuccessHandler.java +++ b/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/handler/SsoLogoutSuccessHandler.java @@ -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); diff --git a/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/service/PigRedisOAuth2AuthorizationService.java b/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/service/PigRedisOAuth2AuthorizationService.java index 8d181895..7e969236 100644 --- a/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/service/PigRedisOAuth2AuthorizationService.java +++ b/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/service/PigRedisOAuth2AuthorizationService.java @@ -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 redisTemplate;