pigx登錄代碼走查


pigx登錄代碼走查

大體流程

6. /oauth/token 接收

  1. 因為發送的是 POST /oauth/token,所以會進入 org.springframework.security.oauth2.provider.endpoint.TokenEndpoint#postAccessToken

  2. 在這個方法里面有個參數是principal,根據調試可以發現,它的實際類型是UsernamePasswordAuthenticationToken。在這個方法里面還有個參數是parameters,它是一個map,里面存放了passwordgrant_typeusername這三個字段

  3. 方法一開始判斷principal是否是org.springframework.security.core.Authentication的子類,不是的話拋出異常,告知用戶增加一個合適的認證過濾器

  4. principal里面實際存儲的是clientIdclientSecret,所以方法從principal里面取出clientId,然后通過ClientDetailsService將數據庫里面的Client詳細信息獲取出來

  5. 用parameters里面的passwordgrant_typeusername,以及剛才獲取到的Client詳細信息(clientIdscopes),構造出一個tokenRequest

  6. 然后方法中寫了一個很奇怪的邏輯,將clientIdtokenRequest.getClientId進行比較。這個比較有意義嗎?難道還會不同?理解不了老外的想法

  7. 對第4步獲取到的Client詳細信息,將它與第5步獲取到的tokenRequest進行比較,比較scope是否合法。太奇怪了,tokenRequest不是從Client詳細信息那里構造出來的嗎?為啥還要判斷scope是否合法?老外的想法太奇怪了

  8. 判斷grant_type是否是implicit,是的話拋出異常,告知用戶/oauth/token不支持implicit方式登錄

  9. 判斷grant_type是否是authorization_code(授權碼模式),並且code是否不為空,是的話說明是授權碼模式登錄,我們用的是password(密碼模式),所以這段邏輯先不看

  10. 判斷grant_type是否是refresh_token(刷新token模式),並且refresh_token是否不為空,是的話說明是刷新token模式,我們用的是password(密碼模式),所以這段邏輯先不看

  11. 取出tokenGranter(我不知道這是啥東西),然后調用它的grant方法,方法的參數是授權類型(也就是password)和第5步生成的tokenRequest

  12. grant方法里面,是調用代理對象delegate(我不太清楚這個是什么東西)的grant方法

  13. 代理對象是CompositeTokenGranter類,它里面有個tokenGranters屬性,該屬性存儲了五個TokenGranter

    其中ResourceOwnerPasswordTokenGranter是我們所需要的TokenGranter

  14. org.springframework.security.oauth2.provider.token.AbstractTokenGranter#grant方法里面,首先會用clientDetailsService.loadClientByClientId取出ClientDetails,驗證這個clientId是否有password(密碼模式)認證類型,沒有的話拋出異常

  15. 使用ClientDetailstokenRequest,調用getAccessToken方法

  16. 調用getOAuth2Authentication方法,進入到org.springframework.security.oauth2.provider.password.ResourceOwnerPasswordTokenGranter#getOAuth2Authentication

  17. tokenRequest中取出usernamepassword,新建出UsernamePasswordAuthenticationToken,再將tokenRequest里面的parameters Map表設置到該token的details屬性里面

  18. 進入org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.AuthenticationManagerDelegator#authenticate。然后再進入到org.springframework.security.authentication.ProviderManager#authenticate

  19. ProviderManager#authenticate方法里面,有兩個AuthenticationProvider,它們分別是AnonymousAuthenticationProviderMobileAuthenticationProvider,恰好兩個Provider的supports方法都表明UsernamePasswordAuthenticationToken不是它們繼承的類,所以這些Provider的authenticate方法是不會進入的

  20. 如果上面兩個都沒有做過認證處理,那么再找父類,讓父類來認證。父類也有providers,它里面只有一個DaoAuthenticationProvider,這個AuthenticationProvider支持UsernamePasswordAuthenticationToken,所以調用DaoAuthenticationProvider的authenticate方法

  21. UsernamePasswordAuthenticationToken取出username。通過usernameuserCache取出UserDetails,如果是null,則調用retrieveUser方法獲取用戶信息,在這個方法里面調用了loadUserByUsername

  22. 對於返回的用戶詳情,首先進行預檢查,依次檢查是否被鎖定、是否被禁用、是否賬號過期。

  23. 然后再進入additionalAuthenticationChecks,在這個方法里面,取出UsernamePasswordAuthenticationToken里面的密碼原文,對比UserDetails里面的密碼密文,使用passwordEncoder.matches進行密碼校驗

  24. 最后進入org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.DefaultPostAuthenticationChecks#check,檢查密碼是否過期

  25. 經過前面三步,都沒有報錯的話,說明用戶輸入的賬號密碼是正確的。將用戶詳情存入緩存。調用createSuccessAuthentication

  26. createSuccessAuthentication方法里面,首先要判斷密碼是否要更新。我們在登錄呢,不需要更新密碼。然后進入父類的createSuccessAuthentication

  27. 在父類的createSuccessAuthentication里面,使用賬號、密碼、權限構造出一個token,再將認證里面的詳情信息(也就是那個Map的信息)寫入token的details里面,返回UsernamePasswordAuthenticationToken

  28. 回到21步,擦除密碼,將密碼廣播出去。返回上級AuthenticationProvider,也擦除一遍密碼,返回認證信息

  29. 很多函數結束返回了,最終又返回到org.springframework.security.oauth2.provider.password.ResourceOwnerPasswordTokenGranter#getOAuth2Authentication,調用getRequestFactory().createOAuth2Request(client, tokenRequest),移除掉map中的password,構造出modifiable,使用new OAuth2Request(modifiable, client.getClientId(), client.getAuthorities(), true, this.getScope(), client.getResourceIds(), null, null, null)生成OAuth2Request

  30. 使用剛才生成的OAuth2Request和28步返回的userAuth,構造出OAuth2Authentication

  31. 返回上層,使用tokenServices.createAccessToken創建token。進入到org.springframework.security.oauth2.provider.token.DefaultTokenServices#createAccessToken(org.springframework.security.oauth2.provider.OAuth2Authentication),調用tokenStore.getAccessToken

  32. tokenStore.getAccessToken里面,先調用authenticationKeyGenerator.extractKey生成一個字符串,在它前面加上auth_to_access:再調用serializeKey,獲取redis連接從里面獲取bytes,將bytes反序列化就是token了…… 我不看了,現在大概意思就是,先看看redis里面有沒有token,有的話返回token;沒有的話,就調用 org.springframework.security.oauth2.provider.token.DefaultTokenServices#createAccessToken(org.springframework.security.oauth2.provider.OAuth2Authentication, org.springframework.security.oauth2.common.OAuth2RefreshToken) 創建token,如果有token增強器就增強token,將token存儲到tokenStore里面,返回token


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM