OAuth2AuthorizationEndpointFilter类介绍、应用场景和示例代码
概述
OAuth2AuthorizationEndpointFilter
是 Spring Security OAuth2 授权服务器中的核心过滤器,负责处理 OAuth2 授权码授权流程中的 /oauth2/authorize
端点请求。
核心功能
-
处理授权请求:验证客户端发起的授权请求参数
-
用户同意流程:处理用户对授权范围的同意操作
-
生成授权码:验证通过后生成授权码返回给客户端
-
错误处理:处理授权过程中的各种错误情况
主要组件和工作流程
1. 请求匹配
-
使用
RequestMatcher
匹配/oauth2/authorize
端点的 GET 和 POST 请求 -
区分授权请求和同意请求:
-
授权请求:包含
response_type
参数 -
同意请求:不包含
response_type
参数
-
2. 认证转换器
-
默认使用
DelegatingAuthenticationConverter
组合两个转换器:-
OAuth2AuthorizationCodeRequestAuthenticationConverter
:转换授权请求 -
OAuth2AuthorizationConsentAuthenticationConverter
:转换同意请求
-
3. 认证管理器
-
使用
AuthenticationManager
处理认证逻辑 -
默认配置了两个认证提供者:
-
OAuth2AuthorizationCodeRequestAuthenticationProvider
:处理授权请求 -
OAuth2AuthorizationConsentAuthenticationProvider
:处理同意请求
-
4. 成功/失败处理器
-
authenticationSuccessHandler
:处理成功认证,默认发送授权响应 -
authenticationFailureHandler
:处理认证失败,默认发送错误响应
5. 同意页面
-
consentPage
:配置自定义同意页面URI
工作流程
-
匹配请求路径和方法
-
使用认证转换器将请求转换为认证对象
-
使用认证管理器进行认证
-
处理认证结果:
-
成功:生成授权码并重定向回客户端
-
需要用户同意:重定向到同意页面
-
失败:返回错误信息
-
应用场景
-
标准授权码流程:处理客户端发起的授权请求
-
自定义同意页面:替换默认的同意页面
-
扩展授权流程:通过自定义转换器或处理器实现特殊业务逻辑
-
OpenID Connect:处理包含
openid
范围的请求
示例代码
基本配置示例
@Configuration
@EnableWebSecurity
public class AuthorizationServerConfig {@Bean@Order(Ordered.HIGHEST_PRECEDENCE)public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {OAuth2AuthorizationServerConfigurer authorizationServerConfigurer =new OAuth2AuthorizationServerConfigurer();http.apply(authorizationServerConfigurer).authorizationEndpoint(authorizationEndpoint -> authorizationEndpoint.consentPage("/oauth2/consent") // 自定义同意页面);return http.build();}
}
自定义同意页面示例
@Controller
public class ConsentController {@GetMapping("/oauth2/consent")public String consent(@RequestParam(OAuth2ParameterNames.SCOPE) String scope,@RequestParam(OAuth2ParameterNames.CLIENT_ID) String clientId,@RequestParam(OAuth2ParameterNames.STATE) String state,Model model) {// 查询客户端信息RegisteredClient registeredClient = registeredClientRepository.findByClientId(clientId);// 解析scopeSet<String> scopes = StringUtils.delimitedListToSet(scope, " ");model.addAttribute("clientId", clientId);model.addAttribute("state", state);model.addAttribute("scopes", scopes);model.addAttribute("clientName", registeredClient.getClientName());return "consent";}@PostMapping("/oauth2/consent")public String approveOrDeny(@RequestParam(OAuth2ParameterNames.SCOPE) String scope,@RequestParam(OAuth2ParameterNames.CLIENT_ID) String clientId,@RequestParam(OAuth2ParameterNames.STATE) String state,@RequestParam String userAction) {if ("approve".equals(userAction)) {// 用户同意授权return "redirect:/oauth2/authorize?" +"client_id=" + clientId +"&state=" + state +"&scope=" + scope;} else {// 用户拒绝授权return "redirect:/oauth2/authorize?" +"client_id=" + clientId +"&state=" + state +"&error=access_denied";}}
}
自定义认证转换器示例
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {OAuth2AuthorizationServerConfigurer authorizationServerConfigurer =new OAuth2AuthorizationServerConfigurer();http.apply(authorizationServerConfigurer).authorizationEndpoint(authorizationEndpoint -> authorizationEndpoint.authenticationConverter(new CustomAuthenticationConverter()));return http.build();
}// 自定义认证转换器
static class CustomAuthenticationConverter implements AuthenticationConverter {@Overridepublic Authentication convert(HttpServletRequest request) {// 自定义转换逻辑if (request.getParameter("custom_param") != null) {// 处理自定义参数return new CustomAuthenticationToken(request);}// 默认处理return new OAuth2AuthorizationCodeRequestAuthenticationConverter().convert(request);}
}
自定义成功处理器示例
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {OAuth2AuthorizationServerConfigurer authorizationServerConfigurer =new OAuth2AuthorizationServerConfigurer();http.apply(authorizationServerConfigurer).authorizationEndpoint(authorizationEndpoint -> authorizationEndpoint.authorizationResponseHandler(new CustomAuthorizationResponseHandler()));return http.build();
}// 自定义成功处理器
static class CustomAuthorizationResponseHandler implements AuthenticationSuccessHandler {private final RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();@Overridepublic void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,Authentication authentication) throws IOException {OAuth2AuthorizationCodeRequestAuthenticationToken authorizationCodeRequestAuthentication =(OAuth2AuthorizationCodeRequestAuthenticationToken) authentication;// 记录授权日志logAuthorization(authorizationCodeRequestAuthentication);// 构建标准响应UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromUriString(authorizationCodeRequestAuthentication.getRedirectUri()).queryParam(OAuth2ParameterNames.CODE,authorizationCodeRequestAuthentication.getAuthorizationCode().getTokenValue());if (StringUtils.hasText(authorizationCodeRequestAuthentication.getState())) {uriBuilder.queryParam(OAuth2ParameterNames.STATE,UriUtils.encode(authorizationCodeRequestAuthentication.getState(), StandardCharsets.UTF_8));}String redirectUri = uriBuilder.build(true).toUriString();this.redirectStrategy.sendRedirect(request, response, redirectUri);}private void logAuthorization(OAuth2AuthorizationCodeRequestAuthenticationToken authentication) {// 实现日志记录逻辑}
}
总结
OAuth2AuthorizationEndpointFilter
是 OAuth2 授权码流程的核心组件,提供了多个扩展点允许开发者自定义:
-
认证转换:通过自定义
AuthenticationConverter
修改请求到认证对象的转换逻辑 -
认证处理:通过自定义
AuthenticationProvider
修改认证逻辑 -
成功处理:通过自定义
AuthenticationSuccessHandler
修改成功响应 -
失败处理:通过自定义
AuthenticationFailureHandler
修改错误响应 -
同意页面:通过配置
consentPage
使用自定义的同意页面
通过这些扩展点,开发者可以灵活地实现各种业务需求,如:
-
添加额外的请求参数验证
-
修改授权码生成逻辑
-
实现自定义的同意页面
-
记录详细的授权日志
-
集成企业特定的认证机制