参数:grant_type、refresh_token、client_id、client_secret
源码解析:
1、grant_type为固定值:grant_type=refresh_token
源码中会根据grant_type是否为refresh_token且refresh_token字段不能为空来判断这个请求是刷新token还是获取token。
2、refresh_token是我们获取token时返回的一个字段用于刷新token
上图为oauth2.0返回token的字段其中包含refresh_token,我们只需要记住这个值,才有可能刷新token。
3、client_id和client_secret字段的获取
我们可以通过请求头的basic认证来从数据库中获取我们所需要的client_id和client_secret字段。
处理HTTP请求中的BASIC authorization头部,把认证结果写入SecurityContextHolder。
当一个HTTP请求中包含一个名字为Authorization的头部,并且其值格式是Basic xxx时,该Filter会认为这是一个BASIC authorization头部,其中xxx部分应该是一个base64编码的{username}:{password}字符串。比如用户名/密码分别为 admin/admin, 则对应的该头部是 : Basic XXXXXXX 。
该过滤器会从 HTTP BASIC authorization头部解析出相应的用户名和密码然后调用AuthenticationManager进行认证,成功的话会把认证了的结果写入到SecurityContextHolder中SecurityContext的属性authentication上面。同时还会做其他一些处理,比如Remember Me相关处理等等。
如果头部分析失败,该过滤器会抛出异常BadCredentialsException。
如果认证失败,则会清除SecurityContextHolder中的SecurityContext。并且不再继续filter chain的执行
org.springframework.security.web.authentication.www.BasicAuthenticationFilter类中处理过程
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
boolean debug = this.logger.isDebugEnabled();
String header = request.getHeader("Authorization");
if (header != null && header.toLowerCase().startsWith("basic ")) {
try {
String[] tokens = this.extractAndDecodeHeader(header, request);
assert tokens.length == 2;
String username = tokens[0];
if (debug) {
this.logger.debug("Basic Authentication Authorization header found for user '" + username + "'");
}
if (this.authenticationIsRequired(username)) {
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, tokens[1]);
authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
Authentication authResult = this.authenticationManager.authenticate(authRequest);
if (debug) {
this.logger.debug("Authentication success: " + authResult);
}
//此处将basic的认证结果存储到了Authentication。
SecurityContextHolder.getContext().setAuthentication(authResult);
this.rememberMeServices.loginSuccess(request, response, authResult);
this.onSuccessfulAuthentication(request, response, authResult);
}
} catch (AuthenticationException var10) {
SecurityContextHolder.clearContext();
if (debug) {
this.logger.debug("Authentication request for failed: " + var10);
}
this.rememberMeServices.loginFail(request, response);
this.onUnsuccessfulAuthentication(request, response, var10);
if (this.ignoreFailure) {
chain.doFilter(request, response);
} else {
this.authenticationEntryPoint.commence(request, response, var10);
}
return;
}
chain.doFilter(request, response);
} else {
chain.doFilter(request, response);
}
}
紧接着我们继续看oauth2.0源码
org.springframework.security.oauth2.provider.endpoint.TokenEndpoint中这样写
@RequestMapping(
value = {"/oauth/token"},
method = {RequestMethod.POST}
)
public ResponseEntity postAccessToken(Principal principal, @RequestParam Map parameters) throws HttpRequestMethodNotSupportedException {
//这里我们将会用到basic认证所存储的对象Authentication
if (!(principal instanceof Authentication)) {
throw new InsufficientAuthenticationException("There is no client authentication. Try adding an appropriate authentication filter.");
} else {
//通过Authentication获取clientld
String clientId = this.getClientId(principal);
//ClientDetailsService可以通过jdbc连接数据库通过clientid查到我们需要的client_secret字段
ClientDetails authenticatedClient = this.getClientDetailsService().loadClientByClientId(clientId);
TokenRequest tokenRequest = this.getOAuth2RequestFactory().createTokenRequest(parameters, authenticatedClient);
if (clientId != null && !clientId.equals("") && !clientId.equals(tokenRequest.getClientId())) {
throw new InvalidClientException("Given client ID does not match authenticated client");
} else {
if (authenticatedClient != null) {
this.oAuth2RequestValidator.validateScope(tokenRequest, authenticatedClient);
}
if (!StringUtils.hasText(tokenRequest.getGrantType())) {
throw new InvalidRequestException("Missing grant type");
} else if (tokenRequest.getGrantType().equals("implicit")) {
throw new InvalidGrantException("Implicit grant type not supported from token endpoint");
} else {
if (this.isAuthCodeRequest(parameters) && !tokenRequest.getScope().isEmpty()) {
this.logger.debug("Clearing scope of incoming token request");
tokenRequest.setScope(Collections.emptySet());
}
if (this.isRefreshTokenRequest(parameters)) {
tokenRequest.setScope(OAuth2Utils.parseParameterList((String)parameters.get("scope")));
}
OAuth2AccessToken token = this.getTokenGranter().grant(tokenRequest.getGrantType(), tokenRequest);
if (token == null) {
throw new UnsupportedGrantTypeException("Unsupported grant type: " + tokenRequest.getGrantType());
} else {
return this.getResponse(token);
}
}
}
}
}
通过clientid获取ClientDetails
public ClientDetails loadClientByClientId(String clientId) throws InvalidClientException {
try {
ClientDetails details = (ClientDetails)this.jdbcTemplate.queryForObject(this.selectClientDetailsSql, new JdbcClientDetailsService.ClientDetailsRowMapper(), new Object[]{clientId});
return details;
} catch (EmptyResultDataAccessException var4) {
throw new NoSuchClientException("No client with requested id: " + clientId);
}
}
(源码中我加的注释不要错过哦)至此刷新token所需要的所有字段我们已经都聚齐了,此时只需要调用接口就可以刷新token了!