Spring Security-01 /oauth/token执行授权流程 分析
内容简介:
个人服务器推荐:
- 腾讯云: 双十一 2核4G 70元/年, 错过等一年!!!
- 阿里云 : 云服务器 2核2G 60元/年, 学生党首推云服务器
- 腾讯云: 云产品限时秒杀,爆款2核4G轻量级云服务器,首年74元
PS: 若文章字体偏大或者偏小,建议通过 ctrl键+鼠标滑轮 进行修改,以提升阅读效果.(带来不便,请谅解!)
Version:
- JDK : 1.8
- 首先 Spring Security 校验用户request 请求. ->spring security filter chain 过滤操作
- TokenEndpoint : /oauth/token 执行授权流程.
简述:
client 信息 认证, -> http basic + spring security filter
授权前端 通过在reqeust header 中添加http basic 中添加client信息 用于 客户端身份认证.
前端: basic64 加密, 内容是test:test
header添加Authorization:Basic dGVzdDp0ZXN0
后端: spring security filter 过滤链处理
oauth2 认证 即 TokenEndpoint的/oauth/token 方法实现用户登录.
Content:
TokenEndpoint:
/oauth/token:
先认证用户,在授权用户信息.
*相当于执行controller层方法.**
前端http请求:
```
```txt
************************************************************
Request received for POST '/oauth/token?randomStr=55271651050219816&code=3&grant_type=password&scope=server':
HttpServletRequestImpl [ POST /oauth/token ]
servletPath:/oauth/token
pathInfo:null
headers:
Origin: http://tx-year
Cookie: JSESSIONID=YomwMhfw67uDUjybVaFpRM4G99obWqJdww2orntS
X-Forwarded-Prefix: /auth
Accept: application/json, text/plain, */*
Referer: http://tx-year/
X-Forwarded-Host: 172.24.93.133:9999
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36
X-Forwarded-Proto: http,http
Accept-Encoding: gzip, deflate
DNT: 1
Pragma: no-cache
X-Forwarded-Port: 9999
isToken: false
Authorization: Basic cGlnOnBpZw==
Cache-Control: no-cache
host: 192.168.80.1:3000
Forwarded: proto=http;host="172.24.93.133:9999";for="172.24.100.1:43090"
X-Forwarded-For: 112.234.54.246,172.24.100.1
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
Content-Length: 30
X-Real-IP: 112.234.54.246
Content-Type: application/x-www-form-urlencoded
pig
Security filter chain: [
WebAsyncManagerIntegrationFilter
SecurityContextPersistenceFilter
HeaderWriterFilter
LogoutFilter
ClientCredentialsTokenEndpointFilter
BasicAuthenticationFilter
RequestCacheAwareFilter
SecurityContextHolderAwareRequestFilter
AnonymousAuthenticationFilter
SessionManagementFilter
ExceptionTranslationFilter
FilterSecurityInterceptor
]
fun
Security filter chain: [
WebAsyncManagerIntegrationFilter
SecurityContextPersistenceFilter
HeaderWriterFilter
LogoutFilter
ClientCredentialsTokenEndpointFilter
BasicAuthenticationFilter
RequestCacheAwareFilter
SecurityContextHolderAwareRequestFilter
AnonymousAuthenticationFilter
SessionManagementFilter
ExceptionTranslationFilter
FilterSecurityInterceptor
]
************************************************************
TokenEndpoint
做了三件事:
根据clientId 获取 Oauth client, ->
ClientDetailsService
构建OauthTOkenRequest
生成Oauth2AccessToken ->
OAuth2AccessToken token = getTokenGranter().grant(tokenRequest.getGrantType(), tokenRequest);
按照request中的授权类型 grant Oauth2AccessToken
如果是password 模式, ->
ResourceOwnerPasswordTokenGranter.grant()
最后会调到
UserDetailsService.loadUserByUsername(username)
@RequestMapping(value = "/oauth/token", method=RequestMethod.POST)
public ResponseEntity<OAuth2AccessToken> postAccessToken(Principal principal, @RequestParam
Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
// 1. 校验用户是否 已认证
if (!(principal instanceof Authentication)) {
throw new InsufficientAuthenticationException(
"There is no client authentication. Try adding an appropriate authentication filter.");
}
// 2. 获取oauth client , 根据clientID
String clientId = getClientId(principal);
ClientDetails authenticatedClient = getClientDetailsService().loadClientByClientId(clientId);
// 3. 构建tokenRequest
TokenRequest tokenRequest = getOAuth2RequestFactory().createTokenRequest(parameters, authenticatedClient);
// 4. client 是否已认证
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");
}
} // 5. scope 校验
if (authenticatedClient != null) {
oAuth2RequestValidator.validateScope(tokenRequest, authenticatedClient);
}
if (!StringUtils.hasText(tokenRequest.getGrantType())) {
throw new InvalidRequestException("Missing grant type");
}
if (tokenRequest.getGrantType().equals("implicit")) {
throw new InvalidGrantException("Implicit grant type not supported from token endpoint");
}
// 5.1grant_type=authorization_code ,清空scope
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());
}
}
// 5.2grant_type=refresh_token ,设置scope
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)));
}
// 6. 验证grant_type,生成 token
OAuth2AccessToken token = getTokenGranter().grant(tokenRequest.getGrantType(), tokenRequest);
if (token == null) {
throw new UnsupportedGrantTypeException("Unsupported grant type: " + tokenRequest.getGrantType());
}
return getResponse(token);
}
总结:
client 信息 认证, -> http basic + spring security filter
授权前端 通过在reqeust header 中添加http basic 中添加client信息 用于 客户端身份认证.
前端: basic64 加密, 内容是test:test
header添加Authorization:Basic dGVzdDp0ZXN0
后端: spring security filter 过滤链处理
oauth2 认证 即 TokenEndpoint的/oauth/token 方法实现用户登录.