暢購商城(九):Spring Security Oauth2
阿新 • • 發佈:2020-08-21
> 好好學習,天天向上
>
> 本文已收錄至我的Github倉庫**DayDayUP**:github.com/RobodLee/DayDayUP,歡迎Star,更多文章請前往:[目錄導航](https://github.com/RobodLee/DayDayUP)
+ [暢購商城(一):環境搭建](https://blog.csdn.net/weixin_43461520/article/details/107095045)
+ [暢購商城(二):分散式檔案系統FastDFS](https://blog.csdn.net/weixin_43461520/article/details/107137843)
+ [暢購商城(三):商品管理](https://blog.csdn.net/weixin_43461520/article/details/107243543)
+ [暢購商城(四):Lua、OpenResty、Canal實現廣告快取與同步](https://blog.csdn.net/weixin_43461520/article/details/107348436)
+ [暢購商城(五):Elasticsearch實現商品搜尋](https://blog.csdn.net/weixin_43461520/article/details/107466286)
+ [暢購商城(六):商品搜尋](https://blog.csdn.net/weixin_43461520/article/details/107579868)
+ [暢購商城(七):Thymeleaf實現靜態頁](https://blog.csdn.net/weixin_43461520/article/details/107728072)
+ [暢購商城(八):微服務閘道器和JWT令牌](https://blog.csdn.net/weixin_43461520/article/details/107817503)
+ [暢購商城(九):Spring Security Oauth2](https://blog.csdn.net/weixin_43461520/article/details/108144023)
## 前言
之前因為沒學過Spring Security和OAuth2.0,所以看這一章的視訊的時候看的一頭霧水。所以花了幾天時間惡補了一下這方面的知識,並且寫了兩篇文章,把這兩部分內容詳細說明了一下。
+ [SpringBoot整合Spring Security](https://blog.csdn.net/weixin_43461520/article/details/107941983)
+ [OAuth2.0分散式系統環境搭建](https://blog.csdn.net/weixin_43461520/article/details/108052891)
下面的內容只是針對於這個專案的,前兩篇文章中說過的內容就不再說了。
## 認證服務介紹
怎麼搭建OAuth2.0我之前的文章已經詳細說過了,這裡直接將資料裡提供的程式碼匯入即可。
![image](https://upload-images.jianshu.io/upload_images/17762126-6bee94d926b4cd32?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
這裡簡單總結一下每個檔案的作用:
+ `AuthorizationServerConfig`
這個是OAuth2.0的認證服務配置。主要有三點,第一是**客戶端資訊配置**,也就是客戶端需要有哪些條件才可以訪問伺服器,比如客戶端id和客戶端金鑰等,可以直接配置到記憶體中,也可以配置從資料庫中讀取;第二是**授權伺服器端點配置**,就是配置認證管理器,令牌儲存方式等;第三個是**授權伺服器的安全配置**,就是配置訪問的限制,比如限制校驗令牌的配置等。
+ `CustomUserAuthenticationConverter`
自定義的UserAuthenticationConverter,繼承自DefaultUserAuthenticationConverter,重寫了**convertUserAuthentication**方法。預設該方法是獲取authentication中的**username**和**許可權資訊**。而我們重寫的方法裡面還獲取了authentication中的**principal**,判斷是不是我們自定義的**UserJwt**,不是的話就呼叫**userDetailsService.loadUserByUsername**去獲取,然後將**userJwt**中的**name**和**id**獲取出來,新增到返回的map中。
+ `UserDetailsServiceImpl`
這個是自定義的認證授權類,實現了**UserDetailsService**介面,並實現了裡面的**loadUserByUsername()**方法。這個方法是根據前端傳進來的使用者名稱去查出對應的使用者資訊。然後交給後續的過濾器去進行使用者身份的驗證。一般這個方法是從資料庫中查詢使用者,但是這裡為了測試就直接new了一個臨時使用者,密碼是 "robod666" ,所以只要前端傳過來的密碼是 “robod666” 就可以正常登入。
+ `WebSecurityConfig`
這個是Spring Security的安全配置類。主要配置了某些對於某些請求的限制。在這個類中,還往Spring容器中注入了**passwordEncoder**和**authenticationManagerBean**供其他類使用。
+ `UserLoginController`
這個是自定義的一個只使用使用者名稱和密碼進行登入的簡化的登入方式。
+ `LoginService`和`LoginServiceImpl`
UserLoginController的Service層。負責新增一些必要的資訊後然後通過**RestTemplate**模擬瀏覽器向伺服器傳送請求獲取令牌資訊。
+ `AuthToken`
封裝了Token的相關資訊。令牌資訊,重新整理token,jwt短令牌。
+ `CookieUtil`
Cookie的工具類。設定Cookie以及根據名稱獲取Cookie資訊。
+ `UserJwt`
使用者資訊。實現了**UserDetails**介面。驗證使用者時用的就是這個類的物件。
+ `changgou.jks`
金鑰證書,可以使用keytool工具生成。
+ `application.yml`
認證服務的配置檔案
```yml
…………
# 配置資訊,給UserLoginController用的
auth:
ttl: 3600 #token儲存到redis的過期時間
clientId: changgou
clientSecret: changgou
cookieDomain: localhost
cookieMaxAge: -1
# 因為採用了非對稱加密,所以這裡配置了金鑰的相關資訊
encrypt:
key-store:
location: classpath:/robod666.jks
secret: robod666
alias: robod666
password: robod666
…………
```
這幾個檔案的作用到這裡就介紹完了。
## 非對稱加密認證
### 認證流程分析
![image](https://upload-images.jianshu.io/upload_images/17762126-419e52f9df6954f8?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
這個是傳統的認證流程,當我們攜帶令牌去訪問資源伺服器的時候,資源服務會將令牌傳送到授權服務中驗證令牌時候合法。這樣做的話無形之中增加的伺服器的壓力,因為多了一次伺服器之間互動的行為,效率低下。
為了提高效率,採用了公鑰私鑰驗證的方式。
![image](https://upload-images.jianshu.io/upload_images/17762126-7f900af9b769fab4?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
授權服務採用私鑰去生成令牌,然後客戶端攜帶令牌向資源伺服器傳送請求。資源伺服器採用公鑰對令牌進行校驗,校驗通過後再進行下一步操作。減少了和授權服務的互動。
公鑰可以儲存在任意的伺服器中,但是私鑰只能儲存在授權服務中。因為有了私鑰後就可以去偽造令牌,降低了安全性。所以採用非對稱加密也是為了提高安全性。
### 生成金鑰證書
我們可以使用keytool工具來生成金鑰對。在準備好的資料夾下,開啟命令列視窗,執行以下內容:
```properties
keytool -genkeypair -alias robod666 -keyalg RSA -keypass robod666 -keystore robod666.jks -storepass robod666
# -alias:金鑰的別名
# -keyalg:使用的hash演算法
# -keypass:金鑰的訪問密碼
# -keystore:金鑰庫檔名,xc.keystore儲存了生成的證書
# -storepass:金鑰庫的訪問密碼
```
然後介面上會出現幾個問題,答案隨便輸,最後輸入 “**y**” 即可生成金鑰。
![image](https://upload-images.jianshu.io/upload_images/17762126-01c8b1a31adfe100?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
把生成的金鑰證書放在認證服務的**resources**目錄下即可。
### 提取公鑰
在安裝好**openssl**後,在金鑰證書所在的目錄下開啟命令列視窗,執行
```properties
keytool -list -rfc --keystore robod666.jks | openssl x509 -inform pem -pubkey
```
![image](https://upload-images.jianshu.io/upload_images/17762126-3624af04d6757c37?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
這樣就可以將公鑰提取出來。在需要使用到公鑰的微服務的resources目錄下建立一個public.key的檔案,把這段內容合併為一行貼上進去。
### 建立及解析令牌
```java
public class JWTTest {
//建立令牌
@Test
public void createJWT() {
ClassPathResource classPathResource = new ClassPathResource("robod666.jks");
KeyStoreKeyFactory keyStoreKeyFactory =
new KeyStoreKeyFactory(classPathResource, "robod666".toCharArray());
KeyPair keyPair = keyStoreKeyFactory.getKeyPair("robod666");
PrivateKey privateKey = keyPair.getPrivate();