文章目录
- 前言
- AuthorizationServerConfigurerAdapter(身份认证服务配置适配器)
- OAuth2AuthorizationServerConfiguration(OAuth2授权服务配置)
- EnableAuthorizationServer(开启身份认证服务)
- AuthorizationServerEndpointsConfigurations身份认证服务站点配置类
- AuthorizationEndpoint (授权码类型端点)
- TokenEndpoint (Token端点)
- CheckTokenEndpoint (检查Token端点)
- AuthorizationServerSecurityConfigurer(授权服务安全配置)
- ClientCredentialsTokenEndpointFilter (客户端认证Token端点过滤器)
- ClientDetailsServiceConfigurer(客户端详情服务配置)
- AuthorizationServerEndpointsConfigurer(授权服务端点配置)
- TokenGranter(Token授权)
- CompositeTokenGranter(综合Token授权)
- AbstractTokenGranter(抽象Token授权)
- RefreshTokenGranter(刷新Token授权)
- AuthorizationCodeTokenGranter(授权码Token授权)
- ResourceOwnerPasswordTokenGranter(密码Token授权)
- ClientCredentialsTokenGranter(客户端凭证Token授权)
- ImplicitTokenGranter(隐式Token授权)
前言
Spring Security OAuth2,认证原理与流程。
- 客户端认证由
ClientCredentialsTokenEndpointFilter
完成客户端身份认证 - 用户授权由:
TokenEndpoint
或AuthorizationEndpoint
完成。 - Token创建、刷新、移除等。
执行流程如下图:
AuthorizationServerConfigurerAdapter(身份认证服务配置适配器)
授权服务安全配置
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
}
客户端详情配置
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
}
授权服务端点配置
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
}
OAuth2AuthorizationServerConfiguration(OAuth2授权服务配置)
默认OAuth2授权服务配置,可以作为参考
EnableAuthorizationServer(开启身份认证服务)
在这个注解中引入了两个配置类AuthorizationServerEndpointsConfiguration和AuthorizationServerSecurityConfiguration
@Import({AuthorizationServerEndpointsConfiguration.class, AuthorizationServerSecurityConfiguration.class})
AuthorizationServerEndpointsConfigurations身份认证服务站点配置类
AuthorizationEndpoint (授权码类型端点)
@Bean
public AuthorizationEndpoint authorizationEndpoint() throws Exception {
AuthorizationEndpoint authorizationEndpoint = new AuthorizationEndpoint();
FrameworkEndpointHandlerMapping mapping = getEndpointsConfigurer().getFrameworkEndpointHandlerMapping();
//用户审批页面
authorizationEndpoint.setUserApprovalPage(extractPath(mapping, "/oauth/confirm_access"));
//异常处理程序提供者
authorizationEndpoint.setProviderExceptionHandler(exceptionTranslator());
//异常页面
authorizationEndpoint.setErrorPage(extractPath(mapping, "/oauth/error"));
//token授权
authorizationEndpoint.setTokenGranter(tokenGranter());
//配置客户端详情
authorizationEndpoint.setClientDetailsService(clientDetailsService);
//身份认证授权码服务
authorizationEndpoint.setAuthorizationCodeServices(authorizationCodeServices());
//OAuth2请求工厂
authorizationEndpoint.setOAuth2RequestFactory(oauth2RequestFactory());
//OAuth2请求校验
authorizationEndpoint.setOAuth2RequestValidator(oauth2RequestValidator());
//用户审批处理程序
authorizationEndpoint.setUserApprovalHandler(userApprovalHandler());
//重定向解析器
authorizationEndpoint.setRedirectResolver(redirectResolver());
return authorizationEndpoint;
}
TokenEndpoint (Token端点)
@Bean
public TokenEndpoint tokenEndpoint() throws Exception {
TokenEndpoint tokenEndpoint = new TokenEndpoint();
//配置客户端详情
tokenEndpoint.setClientDetailsService(clientDetailsService);
//异常处理Handler
tokenEndpoint.setProviderExceptionHandler(exceptionTranslator());
//token授权
tokenEndpoint.setTokenGranter(tokenGranter());
//OAuth2请求工厂
tokenEndpoint.setOAuth2RequestFactory(oauth2RequestFactory());
//OAuth2请求校验
tokenEndpoint.setOAuth2RequestValidator(oauth2RequestValidator());
//设置允许请求方法
tokenEndpoint.setAllowedRequestMethods(allowedTokenEndpointRequestMethods());
return tokenEndpoint;
}
- 由
ClientCredentialsTokenEndpointFilter
完成客户端身份认证 - 从ClientDetailsService中获取客户端详情信息
- 通过OAuth2RequestFactory将请求参数和客户端详情转为TokenRequest
- 如果client不为空,且判断clientId和获取TokenRequest的clientId是否相等
- 获取的客户端详情信息通过OAuth2RequestValidator校验请求域
- 不支持implicit授权模式
- 判断是否授权码类型请求,是需要设置对应的请求域
- 判断是否刷新Token类型请求,是需要设置对应的请求域
- 通过
TokenGranter
完成授权,返回OAuth2AccessToken
@RequestMapping(value = "/oauth/token", method=RequestMethod.POST)
public ResponseEntity<OAuth2AccessToken> postAccessToken(Principal principal, @RequestParam
Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
//由ClientCredentialsTokenEndpointFilter 完成客户端身份认证
if (!(principal instanceof Authentication)) {
throw new InsufficientAuthenticationException(
"There is no client authentication. Try adding an appropriate authentication filter.");
}
//从ClientDetailsService中根据clientId获取客户端详情信息
String clientId = getClientId(principal);
ClientDetails authenticatedClient = getClientDetailsService().loadClientByClientId(clientId);
//通过OAuth2RequestFactory将请求参数和客户端详情转为TokenRequest
TokenRequest tokenRequest = getOAuth2RequestFactory().createTokenRequest(parameters, authenticatedClient);
//如果client不为空,且判断clientId和获取客户端详情的clientId是否相等
if (clientId != null && !clientId.equals("")) {
// Only validate the client details if a client authenticated during this
// request.
if (!clientId.equals(tokenRequest.getClientId())) {
// double check to make sure that the client ID in the token request is the same as that in the
// authenticated client
throw new InvalidClientException("Given client ID does not match authenticated client");
}
}
//获取的客户端详情信息通过OAuth2RequestValidator校验请求域
if (authenticatedClient != null) {
oAuth2RequestValidator.validateScope(tokenRequest, authenticatedClient);
}
if (!StringUtils.hasText(tokenRequest.getGrantType())) {
throw new InvalidRequestException("Missing grant type");
}
// 不支持implicit授权模式
if (tokenRequest.getGrantType().equals("implicit")) {
throw new InvalidGrantException("Implicit grant type not supported from token endpoint");
}
//是否授权码类型请求
if (isAuthCodeRequest(parameters)) {
// The scope was requested or determined during the authorization step
if (!tokenRequest.getScope().isEmpty()) {
logger.debug("Clearing scope of incoming token request");
tokenRequest.setScope(Collections.<String> emptySet());
}
}
//是否刷新Token类型请求
if (isRefreshTokenRequest(parameters)) {
// A refresh token has its own default scopes, so we should ignore any added by the factory here.
tokenRequest.setScope(OAuth2Utils.parseParameterList(parameters.get(OAuth2Utils.SCOPE)));
}
//通过Token授权,返回OAuth2访问Token
OAuth2AccessToken token = getTokenGranter().grant(tokenRequest.getGrantType(), tokenRequest);
if (token == null) {
throw new UnsupportedGrantTypeException("Unsupported grant type: " + tokenRequest.getGrantType());
}
return getResponse(token);
}
CheckTokenEndpoint (检查Token端点)
@Bean
public CheckTokenEndpoint checkTokenEndpoint() {
CheckTokenEndpoint endpoint = new CheckTokenEndpoint(getEndpointsConfigurer().getResourceServerTokenServices());
endpoint.setAccessTokenConverter(getEndpointsConfigurer().getAccessTokenConverter());
endpoint.setExceptionTranslator(exceptionTranslator());
return endpoint;
}
AuthorizationServerSecurityConfigurer(授权服务安全配置)
主要完成功能是安全配置
主要功能:ClientDetailsService转换为UserDetailsService并注入到AuthenticationManager
public void init(HttpSecurity http) throws Exception {
registerDefaultAuthenticationEntryPoint(http);
//将ClientDetailsService转换为UserDetailsService并注入到AuthenticationManager
if (passwordEncoder != null) {
ClientDetailsUserDetailsService clientDetailsUserDetailsService = new ClientDetailsUserDetailsService(clientDetailsService());
clientDetailsUserDetailsService.setPasswordEncoder(passwordEncoder());
http.getSharedObject(AuthenticationManagerBuilder.class)
.userDetailsService(clientDetailsUserDetailsService)
.passwordEncoder(passwordEncoder());
}
else {
http.userDetailsService(new ClientDetailsUserDetailsService(clientDetailsService()));
}
http.securityContext().securityContextRepository(new NullSecurityContextRepository()).and().csrf().disable()
.httpBasic().realmName(realm);
if (sslOnly) {
http.requiresChannel().anyRequest().requiresSecure();
}
}
在配置类中完成ClientCredentialsTokenEndpointFilter
加入到FilterChainProxy中完成客户端身份认证。
@Override
public void configure(HttpSecurity http) throws Exception {
// ensure this is initialized
frameworkEndpointHandlerMapping();
if (allowFormAuthenticationForClients) {
clientCredentialsTokenEndpointFilter(http);
}
for (Filter filter : tokenEndpointAuthenticationFilters) {
http.addFilterBefore(filter, BasicAuthenticationFilter.class);
}
http.exceptionHandling().accessDeniedHandler(accessDeniedHandler);
}
/**
* 完成客户端身份认证
*/
private ClientCredentialsTokenEndpointFilter clientCredentialsTokenEndpointFilter(HttpSecurity http) {
//创建过滤器,并设置匹配地址,默认/oauth/token
ClientCredentialsTokenEndpointFilter clientCredentialsTokenEndpointFilter = new ClientCredentialsTokenEndpointFilter(
frameworkEndpointHandlerMapping().getServletPath("/oauth/token"));
// 设置身份认证管理器,由init()方法中获取的值
clientCredentialsTokenEndpointFilter
.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class));
//OAuth2身份认证进入点
OAuth2AuthenticationEntryPoint authenticationEntryPoint = new OAuth2AuthenticationEntryPoint();
authenticationEntryPoint.setTypeName("Form");
authenticationEntryPoint.setRealmName(realm);
clientCredentialsTokenEndpointFilter.setAuthenticationEntryPoint(authenticationEntryPoint);
clientCredentialsTokenEndpointFilter = postProcess(clientCredentialsTokenEndpointFilter);
//将过滤器加入到HttpSecurity 中
http.addFilterBefore(clientCredentialsTokenEndpointFilter, BasicAuthenticationFilter.class);
return clientCredentialsTokenEndpointFilter;
}
ClientCredentialsTokenEndpointFilter (客户端认证Token端点过滤器)
- 过滤器匹配地址默认:
/oauth/token
- 获取请求参数中的:
client_id
和client_secret
的数据,转换为UsernamePasswordAuthenticationToken
- 通过AuthenticationManager完成客户端身份认证
ClientDetailsServiceConfigurer(客户端详情服务配置)
AuthorizationServerEndpointsConfigurer(授权服务端点配置)
TokenGranter(Token授权)
CompositeTokenGranter(综合Token授权)
List<TokenGranter> tokenGranters
通过代理方式、循环tokenGranters,根据对应的授权模式,找到指定的TokenGranter完成Token授权模式的选择。在执行方法如下:
OAuth2AccessToken grant(String grantType, TokenRequest tokenRequest)
AbstractTokenGranter(抽象Token授权)
/*
* 授权服务Token服务
* 创建Token:OAuth2AccessToken createAccessToken(OAuth2Authentication authentication)
* 刷新Token: OAuth2AccessToken refreshAccessToken(String refreshToken, TokenRequest tokenRequest)
* 获取Token:OAuth2AccessToken getAccessToken(OAuth2Authentication authentication)
*/
AuthorizationServerTokenServices tokenServices;
/*
* 客户端详情服务
* 获取客户端详情信息:ClientDetails loadClientByClientId(String clientId)
*/
ClientDetailsService clientDetailsService;
/*
* OAuth2请求工厂
* 创建OAuth2请求: OAuth2Request createOAuth2Request(ClientDetails client, TokenRequest tokenRequest)
*
*/
OAuth2RequestFactory requestFactory;
/*
* 授权码类型:authorization_code、password、refresh_token、implicit、client_credentials
*/
String grantType
RefreshTokenGranter(刷新Token授权)
AuthorizationCodeTokenGranter(授权码Token授权)
AuthorizationCodeServices
ResourceOwnerPasswordTokenGranter(密码Token授权)
/*
* 授权类型:password
* 身份认证管理
* /
AuthenticationManager