買的網(wǎng)站模板怎么做成都seo學(xué)徒
oauth2
引言
讀了《設(shè)計模式之美》和《鳳凰架構(gòu)》架構(gòu)安全篇之后,決定寫一個OAuth2.0的認(rèn)證流程的Demo,也算是一個階段性的總結(jié),具體原理實現(xiàn)見《鳳凰架構(gòu)》(架構(gòu)安全設(shè)計篇)。
涉及到的源碼可以從https://github.com/WeiXiao-Hyy/oauth2獲取,歡迎Star!
OAuth2.0原理
主要解決的問題
面向解決第三方應(yīng)用(Third-Party Application)的認(rèn)證授權(quán)協(xié)議,使用Token代替用戶密碼作為授權(quán)的憑證。
- 有了令牌之后,哪怕令牌被泄漏,也不會導(dǎo)致密碼的泄漏
- 令牌上可以設(shè)定訪問資源的范圍以及時效性
- 每個應(yīng)用都持有獨立的令牌,哪個失效都不會波及其他
OAuth2.0一共提出了四種不同的授權(quán)方式:
- 授權(quán)碼模式(Authorization Code)
- 隱式授權(quán)模式(Implicit)
- 密碼模式(Resource Owner Password Credentials)
- 客戶端模式(Client Credentials)
本文介紹和實現(xiàn)的是授權(quán)碼方式。
OAuth2.0流程圖
- client請求授權(quán)服務(wù)端,獲取Authorization Code;
- client通過Authorization Code再次請求授權(quán)服務(wù)端,獲取Access Token;
- client通過服務(wù)端返回的Access Token獲取用戶的基本信息。
流程圖如下所示:
第一次使用github賬號應(yīng)用來登陸掘金,需要進行授權(quán)
掘金即是第三方應(yīng)用, 請求GitHub。
注冊一個新的OAuth Application
如果我們需要使用GitHub賬號來關(guān)聯(lián)我們自己的第三方應(yīng)用則需要完整走一遍OAuth2.0流程。
GitHub生成的client_id, client_secret(密鑰), redirect_uri, homepage_url, application_name等等。
clientId如何生成唯一的
在注冊clientId以及申請clientSecret時,如何保證生成的clientId是不重復(fù)的呢?
和JWT以及Cookie-Session對比
參考《鳳凰架構(gòu)》架構(gòu)安全篇 https://icyfenix.cn/architect-perspective/general-architecture/system-security/authorization.html
談?wù)凷tate參數(shù)為什么可以防止CSRF攻擊
觀察GitHub OAuth2.0實現(xiàn)文檔,可以觀察到在authroize
接口需要傳遞一個state參數(shù),并且在redirect_uri重定向時原封不動傳遞回來,所以為什么可以防止CSRF攻擊呢?
核心: 在于授權(quán)服務(wù)端進行token請求綁定時,會從session將本次會話的賬號與生成access_token進行綁定,而對于用戶是誰并不關(guān)心。
案例
- 用戶B登錄
掘金
網(wǎng)站,并且選擇綁定自己的GitHub
賬號; 掘金
網(wǎng)站將用戶B重定向到GitHub
,由于他之前已經(jīng)登錄過GitHub
,所以GitHub
直接向他顯示是否授權(quán)掘金訪問的頁面;- 用戶B在點擊"同意授權(quán)"之后,截獲
GitHub
服務(wù)器返回的含有authorization code
參數(shù)的HTTP響應(yīng); - 用戶B精心構(gòu)造一個Web頁面,它會觸發(fā)
掘金
網(wǎng)站向GitHub
發(fā)起令牌申請的請求,而這個請求中的authorization code
參數(shù)正是上一步截獲到的code
; - 用戶B將這個Web頁面放到互聯(lián)網(wǎng)上,等待或者誘騙受害者用戶A來訪問;
- 用戶A之前登錄了
掘金
網(wǎng)站,只是沒有把自己的賬號和其他社交賬號綁定起來。在用戶A訪問了用戶B準(zhǔn)備的這個Web頁面,令牌申請流程在用戶A的瀏覽器里被順利觸發(fā),掘金
網(wǎng)站從GitHub
那里獲取到access_token
,但是這個token
以及通過它進一步獲取到的用戶信息卻都是攻擊者用戶B; 掘金
網(wǎng)站將用戶B的GitHub
賬號同用戶A的掘金
賬號關(guān)聯(lián)綁定起來,從此以后,用戶B就可以用自己的GitHub
賬號通過OAuth
登錄到用戶A在掘金
網(wǎng)站中的賬號,堂而皇之的冒充用戶A的身份執(zhí)行各種操作;
代碼實現(xiàn)(知識碎片總結(jié))
本部分將開發(fā)過程中遇到的難點記錄下來,具體源碼參考此repo 👍
postman 請求共享session問題
本文為單體應(yīng)用,使用了HttpServletRequest
和HttpSession
方便開發(fā),將相關(guān)的數(shù)據(jù)保存在服務(wù)器的Session中,但是Postman在發(fā)送請求的時候,
不會將其視為同一個連接,導(dǎo)致獲取不到Session中的數(shù)據(jù),需要每次將用戶登陸的Cookie賦值到相應(yīng)的接口上才能獲取到Session中的數(shù)據(jù)。
實現(xiàn)HandlerInterceptor接口完成請求過濾
涉及到接口請求過濾條件時,可以通過實現(xiàn)WebMvcConfigurer
接口來添加過濾規(guī)則,例如:
- 授權(quán)前用戶沒有登陸則需要重定向到登陸頁面
- 如果access_token過期,則需要重新獲取
- …
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {//注意注入bean的寫法@Beanpublic OauthInterceptor oauthInterceptor() {return new OauthInterceptor();}@Beanpublic AuthAccessTokenInterceptor accessTokenInterceptor() {return new AuthAccessTokenInterceptor();}@Beanpublic LoginInterceptor loginInterceptor() {return new LoginInterceptor();}@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(loginInterceptor()).addPathPatterns("/user/**", "/oauth2.0/authorizePage", "/oauth2.0/authorize", "/sso/token");registry.addInterceptor(oauthInterceptor()).addPathPatterns("/oauth2.0/authorize");registry.addInterceptor(accessTokenInterceptor()).addPathPatterns("/api/**");}
}
參考資料
- https://icyfenix.cn/architect-perspective/general-architecture/system-security/
- https://time.geekbang.org/column/intro/100039001
- https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps
- https://juejin.cn/post/6844903668861534215#heading-4
- https://www.jianshu.com/p/c7c8f51713b6