日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

Springsecurity-oauth2之/oauth/token的处理

發布時間:2024/1/17 javascript 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Springsecurity-oauth2之/oauth/token的处理 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

2019獨角獸企業重金招聘Python工程師標準>>>

? ? Springsecurity-oauth2的版本是2.2.1.RELEASE.

? ? 使用postman進行/oauth/token的時候,服務端Springsecurity是怎么處理的呢?

? ? ? ? ? ? ? ? ? ? ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??圖1

? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 圖2

? ? ? ? ? ? ? ? ? ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 圖3

? ? 上面的圖2和圖3,我們就會從服務端獲得token。

? ? 來看BasicAuthenticationFilter的實現,如下List-1所示

? ? List-1

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.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);}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);} }private String[] extractAndDecodeHeader(String header, HttpServletRequest request) throws IOException {byte[] base64Token = header.substring(6).getBytes("UTF-8");byte[] decoded;try {decoded = Base64.getDecoder().decode(base64Token);} catch (IllegalArgumentException var7) {throw new BadCredentialsException("Failed to decode basic authentication token");}String token = new String(decoded, this.getCredentialsCharset(request));int delim = token.indexOf(":");if (delim == -1) {throw new BadCredentialsException("Invalid basic authentication token");} else {return new String[]{token.substring(0, delim), token.substring(delim + 1)};} }

????BasicAuthenticationFilter會判斷request頭部是否有Authorization,且該字段的值是否以"Basic? "開頭,之后獲得"Basic? "后面的值,看extractAndDecodeHeader的實現,得到ClientID和ClientSecrect,之后會調用ClientDetailsService,獲得Client及Client secrect的信息。將得到的Authentication放入SecurityContextHolder.getContext().setAuthentication()放入到Context中,這樣SpringSecurity的FilterChainProxy后續Filter就不會跑出異常,這樣請求就能順利到達處理/oauth/token的EndPoint——看org.springframework.security.oauth2.provider.endpoint.TokenEndpoint。

? ? List-2

@FrameworkEndpoint public class TokenEndpoint extends AbstractEndpoint {......@RequestMapping(value = "/oauth/token", method=RequestMethod.POST) public ResponseEntity<OAuth2AccessToken> postAccessToken(Principal principal, @RequestParam Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {if (!(principal instanceof Authentication)) {throw new InsufficientAuthenticationException("There is no client authentication. Try adding an appropriate authentication filter.");}String clientId = getClientId(principal);ClientDetails authenticatedClient = getClientDetailsService().loadClientByClientId(clientId);TokenRequest tokenRequest = getOAuth2RequestFactory().createTokenRequest(parameters, authenticatedClient);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 clientthrow new InvalidClientException("Given client ID does not match authenticated client");}}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");}if (isAuthCodeRequest(parameters)) {// The scope was requested or determined during the authorization stepif (!tokenRequest.getScope().isEmpty()) {logger.debug("Clearing scope of incoming token request");tokenRequest.setScope(Collections.<String> emptySet());}}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)));}OAuth2AccessToken token = getTokenGranter().grant(tokenRequest.getGrantType(), tokenRequest);if (token == null) {throw new UnsupportedGrantTypeException("Unsupported grant type: " + tokenRequest.getGrantType());}return getResponse(token);}

? ? 如上List-2所示,到了/oauth/token后,還會再次調用ClientDetailService獲取ClientId和ClientSecrect,之后用我們請求的幾個參數,構造TokenRequest,這個類就是POJO,沒有什么。之后用TokenGranter構造OAuth2AccessToken,TokenGranter的OAuth2AccessToken grant(String grantType, TokenRequest tokenRequest)方法,用我們請求的參數,構造OAuth2AccessToken。TokenGranter間接調用ResourceOwnerPasswordTokenGranter,之后調用ProviderManager,ProviderManager再調用AuthenticationManager,AuthenticationManager調用DaoAuthenticationProvider,從數據庫中獲取用戶信息,之后移除password,之后創建Token。

? ? 經過源碼分析,圖3中的access_token是JDK的UUID值,如下List-3中,new?DefaultOAuth2AccessToken時,UUID.randoUUID().toString()的值作為參數傳入。

? ? List-3

public class DefaultTokenServices implements AuthorizationServerTokenServices, ResourceServerTokenServices,ConsumerTokenServices, InitializingBean { ......private OAuth2AccessToken createAccessToken(OAuth2Authentication authentication, OAuth2RefreshToken refreshToken) {DefaultOAuth2AccessToken token = new DefaultOAuth2AccessToken(UUID.randomUUID().toString());int validitySeconds = getAccessTokenValiditySeconds(authentication.getOAuth2Request());if (validitySeconds > 0) {token.setExpiration(new Date(System.currentTimeMillis() + (validitySeconds * 1000L)));}token.setRefreshToken(refreshToken);token.setScope(authentication.getOAuth2Request().getScope());return accessTokenEnhancer != null ? accessTokenEnhancer.enhance(token, authentication) : token; }......

? ? 如List-4所示,先創建OAuth2RefreshToken(是interface,真實是其實現類DefaultOAuth2RefreshToken),在方法createRefreshToken中可以看到,refresh_token的值也是JDK的UUID,之后在創建OAuth2AccessToken(是interface,真實是其實現類DefaultOAuth2AccessToken),傳入作為返回客戶端的refresh_token,也就是圖3中的refresh_token,所以有源碼可知,access_token和refresh_token都是JDK的UUID.randomUUID().toString。

 List-4

@Transactional public OAuth2AccessToken createAccessToken(OAuth2Authentication authentication) throws AuthenticationException {OAuth2AccessToken existingAccessToken = tokenStore.getAccessToken(authentication);OAuth2RefreshToken refreshToken = null;if (refreshToken == null) {refreshToken = createRefreshToken(authentication);}......OAuth2AccessToken accessToken = createAccessToken(authentication, refreshToken);tokenStore.storeAccessToken(accessToken, authentication);......return accessToken;}private OAuth2RefreshToken createRefreshToken(OAuth2Authentication authentication) {if (!isSupportRefreshToken(authentication.getOAuth2Request())) {return null;}int validitySeconds = getRefreshTokenValiditySeconds(authentication.getOAuth2Request());String value = UUID.randomUUID().toString();if (validitySeconds > 0) {return new DefaultExpiringOAuth2RefreshToken(value, new Date(System.currentTimeMillis()+ (validitySeconds * 1000L)));}return new DefaultOAuth2RefreshToken(value); }private OAuth2AccessToken createAccessToken(OAuth2Authentication authentication, OAuth2RefreshToken refreshToken) {DefaultOAuth2AccessToken token = new DefaultOAuth2AccessToken(UUID.randomUUID().toString());int validitySeconds = getAccessTokenValiditySeconds(authentication.getOAuth2Request());if (validitySeconds > 0) {token.setExpiration(new Date(System.currentTimeMillis() + (validitySeconds * 1000L)));}token.setRefreshToken(refreshToken);token.setScope(authentication.getOAuth2Request().getScope());return accessTokenEnhancer != null ? accessTokenEnhancer.enhance(token, authentication) : token; }

? ? 在使用oauth2會遇到clientId、clientSecret、accessTokenValiditySeconds、refreshTokenValiditySeconds、additionalInformation,這些可以在ClientDetails的實現類BaseClientDetails中看到。

????accessTokenValiditySeconds是accessToken過期時間,refreshTokenValiditySeconds是refreshToken過期時間。

????OAuth2AccessTokenJackson1Serializer/OAuth2AccessTokenJackson2Serializer用這個做的序列化,OAuth2AccessToken這個類上有注解。OAuth2AccessToken的實現類DefaultOAuth2AccessToken也只是POJO,并無額外的邏輯,在序列化到HttpResponse時用了jackson的序列化工具,所以我們可以看到返回有access_token、refresh_token字段

轉載于:https://my.oschina.net/u/2518341/blog/3031049

總結

以上是生活随笔為你收集整理的Springsecurity-oauth2之/oauth/token的处理的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。