springboot+spring cloud auth2搭建api接口

基於spring-security-oauth2搭建授權服務器


背景:

  1. 需要API網關控制權限,單點登陸。
  2. 做前後端分離的應用,前端使用vue+elementui實現。

    當前關於這方面的系統資料較少,因此大多是找尋網上零散的示例解析,結合官方文檔中的demo再加上源碼跟蹤調試來進行學習與搭建。但由於涉及的知識點較多,且零散示例中配置或實現方式各有不同,作者經常只會記錄關鍵、核心部分內容,因此會漏掉一些基礎配置信息,給初學者帶來極大困難。往往按照多個示例拼湊出來的demo無法正常運行,或者不明就裏。官方給出的文檔又需要具備一定英文功底。綜合以上因素,這篇文章橫空出世:)

    既包含周邊理論知識淺析,又包含實際案例demo完整代碼(爲了保證下載即可正常運行已附上SQL語句)

涉及知識點:

  1. Oauht2基礎知識(授權類型,運行流程)
  2. 服務器證書,Keytool工具基本使用(常用命令參數解析及證書類別)
  3. SpringBoot項目增加https支持(https協議簡單概述)
  4. Springsecurity知識(spring-security-oauth2是基於springsecurit的,很多配置相關都是沿用springsecurity的)
  5. 具體項目實現(包含服務端及客戶端具體實現,鑑權、SSO)

Oauht2基礎知識

   既然是要搭建基於spring-security-oauth2的授權服務器,那Oauth2的基礎原理和運行流程我們還是需要了解一下的,否則對於授權模式選擇和認證授權流程會比較暈。對於Oauth2的介紹這裏強烈推薦: 理解OAuth2.0,在這裏只簡單描述和摘抄部分關鍵信息.

核心角色介紹

  1. 三方客戶端
  2. 資源所有者
  3. 認證服務器
  4. 資源服務器

    爲了便於理解,這裏舉一個大家耳熟能詳的應用場景來介紹各個角色在實際應用中是如何交互的:在一個愉快的週六午後,小明同學吃完午飯就迫不及待的躺在牀上,拿起手機打開吃雞遊戲(三方客戶端),爲了便於同朋友開黑,小明選擇了微信登陸的方式,這時候吃雞遊戲(三方客戶端)跳轉到一個微信登陸認證頁面(認證服務器),在這裏小明(資源所有者)輸入賬號密碼(身份認證),登陸成功後界面上顯示:是否授權使吃雞遊戲可以訪問你的微信頭像、暱稱、好友資料等。(授權)。授權通過後,剩下是後臺處理,用戶不可見(返回給客戶端一個授權碼,客戶端拿到授權碼結合開始申請授權時的APPKEY申請TOKEN,通過後客戶端憑着這個TOKEN去資源服務器獲取用戶頭像、暱稱等信息)

客戶端的授權模式

  1. 授權碼模式(authorization code)
  2. 簡化模式(implicit)
  3. 密碼模式(resource owner password credentials)
  4. 客戶端模式(client credentials)

    關於這4種授權模式的區別,詳細內容請參見[OAuth2.0](http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html "OAuth2.0"),在這裏我給出了自己比較土的解釋:

    授權碼模式:安全性最高,也是比較常用的方式,但是整個流程最長。運行流程見上面舉的“吃雞”遊戲登陸授權例子。
    簡化模式: 跳過了獲取授權碼的環節,後續流程同授權碼模式。
    密碼模式:把賬號密碼給到客戶端程序,由客戶端程序去請求認證服務器獲取token,這種方式客戶端是能夠獲取到用戶名、密碼信息的。
    客戶端模式:這種其實就和用戶授權沒什麼關係,需要認證的主體是客戶端本身了,客戶端本身以自己的名義去找認證服務器要授權。

服務器證書,Keytool工具基本使用

   涉及到鑑權,當然少不了https的應用。在使用https前,需要創建服務器證書,關於證書這部分的詳細內容請參見:[HTTPS與SSL證書概要](http://www.runoob.com/w3cnote/https-ssl-intro.html "HTTPS與SSL證書概要")

本文中,選擇使用keytool工具來自己動手生成一個。由於springboot默認只支持jks和p12格式的。在此我們選擇生成jks格式的證書,命令如下(需要注意的是得用管理員權限打開cmd命令行,否則生成keystore文件會失敗,報filenotfound錯誤)

  1. 選用JKS的證書,生成語句:
    keytool -genkeypair -alias server -keyalg RSA -validity 3650 -keystore server.jks

其中需要特別注意到的是,在輸入以上命令後,會要求你寫名稱、區域等信息,如下圖
blob.jpg
這裏的姓氏、名稱是你的域名,如果域名與證書內容不符,訪問時將報SSLHandshakeException: 由此可知是ssl 握手失敗!的錯誤.

  1. 導出cer證書(給到第三步導入用的)
    keytool -export -alias server -keystore server.jks -rfc -file server.cer
  2. 導入到jdk中
    keytool -import -alias server -file server.cer -keystore cacerts
    生成文件如下:
    blob.jpg

踩坑爬坑

Bad Request This combination of host and port requires TLS

使用 http://localhost:8081/oauth/authorize?client_id=erpmanager&response_type=code&redirect_uri=www.forever24.cn 獲取code碼時返回報錯信息
blob.jpg
解決方案:返回信息告訴我們,表示需要通過https來訪問,用https://localhost:8081/oauth/authorize?client_id=testcode&response_type=code&redirect_uri=www.forever24.cn訪問結果如下:

blob.jpg
選擇信任後,轉到登陸頁面如下,這個登陸頁面可以直接替換成自己的(需要自己寫登陸頁面,否則默認就是這個簡陋的)
blob.jpg
client信息讀取有in-memory,jdbc等多種方式,這裏採用的是jdbc方式,簡單來說就是自己從數據庫中查詢看然後跟用戶輸入的賬號密碼比對,需要自己重寫UserService部分
blob.jpg
輸入賬號密碼後,滿懷期待😊 ,but:又報錯了,奶奶的熊,明明輸入的賬號密碼是正確的爲什麼還報 Handling ClientRegistrationException error: No client with requested id: erpmanager 的錯呢?
blob.jpg blob.jpg
而且,自己寫的 SupplierInfo supplierInfo = supplierManRepository.findByuserName(username); 查詢user信息中,明明用戶名密碼填寫是對的,也有erpmanager這個用戶 根據報錯信息,顯示的是2019-01-10 11:22:15.974 INFO 9444 --- [nio-8081-exec-4] o.s.s.o.p.e.AuthorizationEndpoint : Handling ClientRegistrationException error: No client with requested id: erpmanager根據關鍵字搜索可以找到,報錯信息是從org.springframework.security.oauth2.provider.endpoint.AuthorizationEndpoint報出來的,並且訪問的是oauth/authorize,可以找到這個url對應的處理方法。
blob.jpg

獲取code碼,身份驗證的代碼在:
blob.jpg
獲取token的入口代碼在:
blob.jpg

Full authentication is required to access this resourceunauthorized
數據庫表說明(使用spring-oauth-server的系統表):http://andaily.com/spring-oauth-server/db_table_description.html

關於SecurityConfig 的配置,需要先了解 構造器模式,否則比較難以理解。可以參見 https://www.cnblogs.com/iCanhua/p/8636085.html

    @Override
    protected void configure(HttpSecurity http) throws Exception { // @formatter:off
        http.requestMatchers().antMatchers("/login", "/oauth/authorize")
            .and().authorizeRequests().anyRequest().authenticated()
            .and().formLogin().permitAll();
    } // @formatter:on

豁然開朗,查下數據庫的[oauth_client_details]表,發現根本沒有設置 erpmanager 這個用戶。 blob.jpg

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章