基于 Spring Security OAuth2和 JWT 构建保护微服务系统
我們希望自己的微服務能夠在用戶登錄之后才可以訪問,而單獨給每個微服務單獨做用戶權限模塊就顯得很弱了,從復用角度來說是需要重構的,從功能角度來說,也是欠缺的。尤其是前后端完全分離之后,我們的用戶信息不一定存在于 Session 會話中。
?
應用場景
常見的應用場景如下圖,用戶通過瀏覽器進行登錄,一旦確定用戶名和密碼正確,那么在服務器端使用秘鑰創建 JWT,并且返回給瀏覽器;接下來我們的請求需要在頭部增加 jwt 信息,服務器端進行解密獲取用戶信息,然后進行其他業務邏輯處理,再返回客戶端
?
?
什么是OAuth2?
OAuth2是一個關于授權的開放標準,核心思路是通過各類認證手段(具體什么手段OAuth2不關心)認證用戶身份,并頒發token(令牌),使得第三方應用可以使用該令牌在限定時間、限定范圍訪問指定資源。主要涉及的RFC規范有RFC6749(整體授權框架),RFC6750(令牌使用),RFC6819(威脅模型)這幾個,一般我們需要了解的就是RFC6749。獲取令牌的方式主要有四種,分別是授權碼模式,簡單模式,密碼模式和客戶端模式,如何獲取token不在本篇文章的討論范圍,我們這里假定客戶端已經通過某種方式獲取到了access_token,想了解具體的oauth2授權步驟可以移步阮一峰老師的理解OAuth 2.0,里面有非常詳細的說明。
這里要先明確幾個OAuth2中的幾個重要概念:
-
resource owner: 擁有被訪問資源的用戶
-
user-agent: 一般來說就是瀏覽器
-
client: 第三方應用
-
Authorization server: 認證服務器,用來進行用戶認證并頒發token
-
Resource server:資源服務器,擁有被訪問資源的服務器,需要通過token來確定是否有權限訪問
明確概念后,就可以看OAuth2的協議握手流程,摘自RFC6749
?
什么是Spring Security?
Spring Security是一套安全框架,可以基于RBAC(基于角色的權限控制)對用戶的訪問權限進行控制,核心思想是通過一系列的filter chain來進行攔截過濾,以下是ss中默認的內置過濾器列表,當然你也可以通過custom-filter來自定義擴展filter chain列表
| CHANNEL_FILTER | ChannelProcessingFilter | http/intercept-url@requires-channel |
| SECURITY_CONTEXT_FILTER | SecurityContextPersistenceFilter | http |
| CONCURRENT_SESSION_FILTER | ConcurrentSessionFilter | session-management/concurrency-control |
| HEADERS_FILTER | HeaderWriterFilter | http/headers |
| CSRF_FILTER | CsrfFilter | http/csrf |
| LOGOUT_FILTER | LogoutFilter | http/logout |
| X509_FILTER | X509AuthenticationFilter | http/x509 |
| PRE_AUTH_FILTER | AbstractPreAuthenticatedProcessingFilter | N/A |
| CAS_FILTER | CasAuthenticationFilter | N/A |
| FORM_LOGIN_FILTER | UsernamePasswordAuthenticationFilter | http/form-login |
| BASIC_AUTH_FILTER | BasicAuthenticationFilter | http/http-basic |
| SERVLET_API_SUPPORT_FILTER | SecurityContextHolderAwareRequestFilter | http/@servlet-api-provision |
| JAAS_API_SUPPORT_FILTER | JaasApiIntegrationFilter | http/@jaas-api-provision |
| REMEMBER_ME_FILTER | RememberMeAuthenticationFilter | http/remember-me |
| ANONYMOUS_FILTER | AnonymousAuthenticationFilter | http/anonymous |
| SESSION_MANAGEMENT_FILTER | SessionManagementFilter | session-management |
| EXCEPTION_TRANSLATION_FILTER | ExceptionTranslationFilter | http |
| FILTER_SECURITY_INTERCEPTOR | FilterSecurityInterceptor | http |
| SWITCH_USER_FILTER | SwitchUserFilter | N/A |
這里面最核心的就是FILTER_SECURITY_INTERCEPTOR,通過FilterInvocationSecurityMetadataSource來進行資源權限的匹配,AccessDecisionManager來執行訪問策略。
認證與授權(Authentication and Authorization)
一般意義來說的應用訪問安全性,都是圍繞認證(Authentication)和授權(Authorization)這兩個核心概念來展開的。即首先需要確定用戶身份,在確定這個用戶是否有訪問指定資源的權限。認證這塊的解決方案很多,主流的有CAS、SAML2、OAUTH2等(不巧這幾個都用過-_-),我們常說的單點登錄方案(SSO)說的就是這塊,授權的話主流的就是spring security和shiro。shiro我沒用過,據說是比較輕量級,相比較而言spring security確實架構比較復雜。
?
OAuth2與SSO
首先要明確一點,OAuth2并不是一個SSO框架,但可以實現SSO功能。
所以總結一下就是:通過將用戶信息這個資源設置為被保護資源,可以使用OAuth2技術實現單點登陸(SSO),而Spring Security OAuth2就是這種OAuth2 SSO方案的一個實現。
?
JWT介紹
終于來到了著名的JWT部分了,JWT全稱為Json Web Token,最近隨著微服務架構的流行而越來越火,號稱新一代的認證技術。今天我們就來看一下,jwt的本質到底是什么。
我們先來看一下OAuth2的token技術有沒有什么痛點,相信從之前的介紹中你也發現了,token技術最大的問題是不攜帶用戶信息,且資源服務器無法進行本地驗證,每次對于資源的訪問,資源服務器都需要向認證服務器發起請求,一是驗證token的有效性,二是獲取token對應的用戶信息。如果有大量的此類請求,無疑處理效率是很低的,且認證服務器會變成一個中心節點,對于SLA和處理性能等均有很高的要求,這在分布式架構下是很要命的。
JWT就是在這樣的背景下誕生的,從本質上來說,jwt就是一種特殊格式的token。普通的oauth2頒發的就是一串隨機hash字符串,本身無意義,而jwt格式的token是有特定含義的,分為三部分:
-
頭部Header
-
載荷Payload
-
簽名Signature
這三部分均用base64進行編碼,當中用.進行分隔,一個典型的jwt格式的token類似xxxxx.yyyyy.zzzzz。關于jwt格式的更多具體說明,不是本文討論的重點,大家可以直接去官網查看官方文檔,這里不過多贅述。
jwt相對于傳統的token來說,解決以下兩個痛點:
-
通過驗證簽名,token的驗證可以直接在本地完成,不需要連接認證服務器
-
在payload中可以定義用戶相關信息,這樣就輕松實現了token和用戶信息的綁定
在上面的那個資源服務器和認證服務器分離的例子中,如果認證服務器頒發的是jwt格式的token,那么資源服務器就可以直接自己驗證token的有效性并綁定用戶,這無疑大大提升了處理效率且減少了單點隱患。
JWT適用場景與不適用場景
JWT的使用上現在也有一種誤區,認為傳統的認證方式都應該被jwt取代。事實上,jwt也不能解決一切問題,它也有適用場景和不適用場景。
適用場景:
-
一次性的身份認證
-
api的鑒權
這些場景能充分發揮jwt無狀態以及分布式驗證的優勢
不適用的場景:
-
傳統的基于session的用戶會話保持
不要試圖用jwt去代替session。這種模式下其實傳統的session+cookie機制工作的更好,jwt因為其無狀態和分布式,事實上只要在有效期內,是無法作廢的,用戶的簽退更多是一個客戶端的簽退,服務端token仍然有效,你只要使用這個token,仍然可以登陸系統。另外一個問題是續簽問題,使用token,無疑令續簽變得十分麻煩,當然你也可以通過redis去記錄token狀態,并在用戶訪問后更新這個狀態,但這就是硬生生把jwt的無狀態搞成有狀態了,而這些在傳統的session+cookie機制中都是不需要去考慮的。這種場景下,考慮高可用,我更加推薦采用分布式的session機制,現在已經有很多的成熟框架可供選擇了(比如spring session)。
?
基于Spring Security OAuth2和JWT構建保護微服務系統
本工程代碼是基于簡書一文基于 Spring Security OAuth2和 JWT 構建保護微服務系統所編寫的。
目錄說明
ljl-architecture-spring-cloud 基于Dalston.SR5版本Spring Cloud + 1.5.13.RELEASE版本Spring Boot去構建。
ljl-architecture-spring-cloud2 基于Finchley.SR2版本Spring Cloud + 2.0.8.RELEASE版本Spring Boot構建。
?
github地址:
https://github.com/leslie-1994/spring-security-oauth2-jwt-demo
總結
以上是生活随笔為你收集整理的基于 Spring Security OAuth2和 JWT 构建保护微服务系统的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: docker环境安装,镜像和容器常用命令
- 下一篇: Windows 上配置Docker De