微服務API開放受權平臺的設計與實現

本文所介紹的項目是一個基於oath2協議的應用,實現的的功能邏輯與QQ互聯微博開放平臺相似,都是同一套認證受權流程。java

項目結構簡單易懂,卻不偷工減料,在學習完本文內容後,讀者能夠直接獲取文中的項目代碼用於學習或者copy到公司的生產項目中修改後使用,真正達到學以至用的目的。git

所涉及技術棧:github

  • java
  • springboot 2.0.1.RELEASE
  • spring security 2.0.1.RELEASE
  • spring cloud oauth2 2.0.0.M7
  • mybatis 2.0.1

本項目包括功能有web

  • 新用戶
  1. 用戶註冊自動分配角色權限
  2. 用戶只能訪問本身所擁有的角色權限訪問路徑
  • 開放平臺
  1. 用戶能夠申請獲取客戶ID和客戶密鑰
  2. 用戶能夠經過客戶ID獲取受權碼
  3. 用戶能夠經過客戶ID和密鑰以及受權碼獲取access token 和referrsh token和scope
  • 資源api服務(order-service/open-api-service)
  1. 可自定義配置需受權url
  2. 可自定義配置受限url的訪問scope
  3. 未受權用戶或訪問權限不足用戶,頁面提示相信息
  4. 用戶經過access token 來訪問對應url

項目概覽

首先來看一下項目的結構圖,瞭解項目的大體佈局spring

  • .idea:idea工具生成的文件
  • docker: 存放Dockerfile文件用於構建容器鏡像
  • config: 項目中關於spring security和web的配置
  • controller:請求控制器
  • entity: 對象實體類包
  • handler:邏輯處理類包
  • mapper:存放mybatis mapper接口類
  • service: 業務邏輯處理類
  • util: 通用的工具類
  • postman:postman工具的測試用例
  • sql:項目的初始化sql語句
  • templates: 頁面模板文件

接下來正式介紹關於項目的細節,因爲項目自己就已經有很多中文註釋,因此在講解的時候會收縮起一些代碼的具體實現,若是讀者不習慣能夠在這裏點在線比對閱讀或者fork到本身的項目裏閱讀==> 項目代碼sql

用戶是如何被攔截認證的

  1. 自定類 SecurityConfig 繼承了 WebSecurityConfigurerAdapter,說明SecurityConfig將會是一個 Http安全配置適配器
  2. 經過 @EnableWebSecurity打開了 HttpSecurity 的安全配置,則該類將生效

  1. 重寫 WebSecurityConfigurerAdapter 的 configure(HttpSecurity http) 方法
  2. 指定哪裏請求url是不須要攔截直接放行的
  3. 指定哪些請求是須要攔截校驗的

  1. 重寫 WebSecurityConfigurerAdapter 的 configure(AuthenticationManagerBuilder auth) 方法
  2. 指定處理認證的service服務類爲 MyUserDetailsService
  3. 比對輸入的密碼和數據庫中的用戶密碼是否一致

  1. 自定類 MyUserDetailsService 實現了 spring security的UserDetailsService 接口
  2. 重寫 loadUserByUsername(String username) 方法, 其中username是頁面傳的屬性和值,屬性是固定的
  3. 獲取用戶權限表對應的權限詳情,並把內容設置到 UserDetails.Authorities屬性中
  4. 返回 UserDetails的子類 User

用戶註冊自動分配角色權限

用戶註冊則往用戶表插入數據,同時往用戶角色表也插入一份數據。
固然也能夠設計的更復雜些,好比根據來源、時間、白名單、內部推薦等設置不一樣的權限,讀者可自行擴展。 docker

用戶只能訪問本身所擁有的角色權限訪問路徑

  1. 取出當前用戶的全部權限
  2. 取出權限的權限標識字段,幷包裝成一個List 集合
  3. 保存包裝的權限list集合到 UserDetails 對象中

  1. 取出全部權限表中內容
  2. http.authorizeRequests()獲取當前的認證對象
  3. 把權限表中的內容所有設置到 authorizeRequests中, antMatchers表示攔截的url, hasAnyAuthority表示能夠訪問的權限標識
  4. 由於在上圖中user已經設置了本身所擁有權限的權限標識,因此能夠訪問被攔截的url

用戶能夠申請獲取客戶ID和客戶密鑰

首先來看一下表結構,oauth_client_details 爲spring cloud oath2自帶的表, user_client_secret 爲咱們本身建立的表 數據庫

  1. 生成 OauthClientDetails 數據並保存至數據庫中
  2. 獲取當前登陸人信息,並綁定OauthClientDetails的clientId至user_client_secret表中

用戶能夠經過客戶ID獲取受權碼

具體的實如今spring-security-oauth包中的, 非本項目內的自我實現api

客戶ID獲取受權碼 請求url: http://localhost:8080/oauth/authorize?response_type=code&client_id=client_92&redirect_uri=http://localhost:8080/code安全

  1. 由於是要獲取受權碼,response_type=code爲固定值
  2. 客戶申請的客戶ID
  3. oauth_client_details 表中的 web_server_redirect_uri

用受權碼獲取access_token

具體的實如今spring-security-oauth包中的 org.springframework.security.oauth2.provider.endpoint.TokenEndpoint類,有興趣的同窗能夠在裏面進行debug調試

用受權碼獲取access_token 請求url: http://localhost:8080/oauth/token?grant_type=authorization_code&code=8fGtOV&client_id=client_92&client_secret=123456&redirect_uri=http://localhost:8080/code&scope=all

  1. 經過客戶ID獲取到的受權碼
  2. 客戶申請的客戶ID
  3. 客戶申請的客戶ID配套的客戶祕鑰
  4. oauth_client_details 表中的 web_server_redirect_uri
  5. oauth_client_details 表中的 scope
# 出現以下相似錯誤標識code失效,從新在獲取受權碼操做便可
{
    "error": "invalid_grant",
    "error_description": "Invalid authorization code: iq30f9"
}
複製代碼

商戶id和商戶祕鑰獲取accessToken和刷新accessToken

  • grant_type: 受權類型,這裏設置爲密碼模式
  • username: 用戶名
  • password: 用戶密碼
  • client_id: 申請獲得的客戶Id
  • client_secret: 申請獲得的客戶祕鑰
  • scope:範圍標識,取自 oauth_client_details 表中的 scope

刷新 accessToken

刷新 accessToken的 請求url: http://localhost:8080/oauth/token?grant_type=refresh_token&refresh_token=4741d043-e202-4de0-ae21-4f5c7ec5626e&client_id=client_1&client_secret=123456

驗證accessToken是否有效

驗證accessToken的 請求url: http://localhost:8080/oauth/check_token?token=1131809b-ee12-4aea-9823-ea4454b96f2d

資源api服務

到了這裏,咱們來看另外一個項目 order-service, 其實取名叫 order-api-resource 比較合適,不過也懶得改了。這個項目的結構與代碼比較稀少,因此學習起來更爲輕鬆。

如何自定義配置需攔截受權的url

經過 antMatchers()authenticated() 方法來配置,查看圖中紅框內的內容, 這些都是表明須要攔截驗證的請求路徑url,除了攔截請求外,還能夠指定攔截請求方式,好比訪問 /api/trade/ ,只對 POST 訪問作攔截, GET 請求的訪問一概放行。

如何自定義配置受限url的訪問scope

經過 access() 方法指定訪問的該 url 須要的 scope,取值爲 oauth_client_details 表中的 scope 值, 若是scope值與代碼中定義的不一致,則會出現以下錯誤:

未受權用戶或訪問權限不足用戶,頁面提示相應信息

用戶如何經過 access token 來訪問對應url

  1. 配置驗證 accessToken 是否有效的服務地址,其實就是上面發放 accessToken 的服務
  2. 須要配置商戶id和商戶祕鑰獲取accessToken,用來經過的開發平臺的校驗。有的小夥伴可能奇怪了,文中上面也有介紹驗證accessToken是否有效,可是並無須要驗證登陸,這裏爲何要呢? 咱們來看下源碼:

spring-security-oauth2-2.2.1.RELEASE-sources.jar 中的 RemoteTokenServices.java 用於遠程調用 token 服務(開發平臺)進行操做

  1. 由於給http header 設置了Authorization屬性表示須要驗證,因此取了上述配置中的 clientId 和 clientSecret,不然發送請求會被開放平臺驗證失敗
  2. postForMap() 包裝參數並執行請求發送

項目代碼點這裏

問題

/oauth/check_token 401

相關文章
相關標籤/搜索