Oauth2授權,熟悉微信開發的同學對這個東西應該不陌生吧。當我們的應用系統需要集成第三方授權時一般都會做oauth集成,今天就來看看在Dapr的語境下我們如何僅通過配置無需修改應用程序的方式讓第三方服務保護我們的API應用。
目錄:
一、通過Dapr實現一個簡單的基於.net的微服務電商系統
二、通過Dapr實現一個簡單的基於.net的微服務電商系統(二)——通訊框架講解
三、通過Dapr實現一個簡單的基於.net的微服務電商系統(三)——一步一步教你如何擼Dapr
四、通過Dapr實現一個簡單的基於.net的微服務電商系統(四)——一步一步教你如何擼Dapr之訂閱發布
五、通過Dapr實現一個簡單的基於.net的微服務電商系統(五)——一步一步教你如何擼Dapr之狀態管理
六、通過Dapr實現一個簡單的基於.net的微服務電商系統(六)——一步一步教你如何擼Dapr之Actor服務
七、通過Dapr實現一個簡單的基於.net的微服務電商系統(七)——一步一步教你如何擼Dapr之服務限流
八、通過Dapr實現一個簡單的基於.net的微服務電商系統(八)——一步一步教你如何擼Dapr之鏈路追蹤
九、通過Dapr實現一個簡單的基於.net的微服務電商系統(九)——一步一步教你如何擼Dapr之OAuth2授權 && 百度版Oauth2
十、通過Dapr實現一個簡單的基於.net的微服務電商系統(十)——一步一步教你如何擼Dapr之綁定
十一、通過Dapr實現一個簡單的基於.net的微服務電商系統(十一)——一步一步教你如何擼Dapr之自動擴/縮容
十二、通過Dapr實現一個簡單的基於.net的微服務電商系統(十二)——istio+dapr構建多運行時服務網格
十三、通過Dapr實現一個簡單的基於.net的微服務電商系統(十三)——istio+dapr構建多運行時服務網格之生產環境部署
十四、通過Dapr實現一個簡單的基於.net的微服務電商系統(十四)——開發環境容器調試小技巧
十五、通過Dapr實現一個簡單的基於.net的微服務電商系統(十五)——集中式接口文檔實現
十六、通過Dapr實現一個簡單的基於.net的微服務電商系統(十六)——dapr+sentinel中間件實現服務保護
十七、通過Dapr實現一個簡單的基於.net的微服務電商系統(十七)——服務保護之動態配置與熱重載
十八、通過Dapr實現一個簡單的基於.net的微服務電商系統(十八)——服務保護之多級緩存
十九、通過Dapr實現一個簡單的基於.net的微服務電商系統(十九)——分布式事務之Saga模式
二十、通過Dapr實現一個簡單的基於.net的微服務電商系統(二十)——Saga框架實現思路分享
附錄:(如果你覺得對你有用,請給個star)
一、電商Demo地址
Dapr目前支持兩種Oauth2授權,一種是用戶認證模式,一種是客戶端憑據模式。今天的演示主要是通過集成github用戶認證的模式來實現相關功能,先上流程圖:
流程圖畫的比較簡單,而且這里隱藏了dapr相關的細節,下面我們詳細看看到底發生了什么:
1、首先訪問者通過客戶端發起一個對鑒權服務的訪問,sidecar檢測到此次訪問沒有對應cookie則會發起一個重定向到github的302請求。
2、客戶端檢測到302后會重定向到github,github會展示一個登錄頁面並提示訪問者登錄並授權給應用使用相關能力(如獲取用戶信息),授權完成后github帶上code並發起一個302重定向回到我們提前錄入好的回調地址,該地址實際上也是指向我們的鑒權服務。
3、鑒權服務的sidecar拿到對應code后會再次請求github拿到accesstoken並通過header的方式將該accesstoken返回給應用。
4、應用拿到accesstoken后就可以訪問github公開的api獲取訪問者授權部分的功能。
基本邏輯如上,下面我們看看如何集成github,首先我們需要登錄github創建一個對應的應用:
登錄你的github賬號,並在右上角賬號頭像上點擊進入setting,進入設置頁面后在左側菜單欄選擇“Developer settings”並選擇二級菜單“OAuth Apps”,在這里我們需要創建一個應用,創建應用比較簡單,這里唯一需要注意的是Authorization callback URL這一欄需要輸入授權地址。不過創建時可以隨意填寫一個地址,等后續授權服務上線后再修改這里的回調地址即可。創建完成后我們可以進入detail拿到兩個關鍵配置Client ID、Client secrets。
接着我們創建對應的Component並錄入剛才拿到的Client ID、Client secrets:注意這里的redirectURL如果填了的話,跳轉會按照這里填寫的地址跳轉,否則按照應用上預設的地址跳轉,我這里留空。另外authHeaderName是我們告訴daprd回調拿到的accesstoken的header名字自定義為“myauth”,否則會使用默認的關鍵字“authorization”,如果你不想占用該關鍵字則可以聲明一個自定義headername。
apiVersion: dapr.io/v1alpha1 kind: Component metadata: name: githubauth namespace: dapreshop spec: type: middleware.http.oauth2 version: v1 metadata: - name: clientId value: "your client id" - name: clientSecret value: "your client secret" - name: scopes value: "user:email" - name: authURL value: "https://github.com/login/oauth/authorize" - name: tokenURL value: "https://github.com/login/oauth/access_token" - name: redirectURL value: "" - name: authHeaderName value: "myauth"
接着我們申明一個Configuration並注入到鑒權服務中(注入部分參考之前的限流)
apiVersion: dapr.io/v1alpha1 kind: Configuration metadata: name: appconfig namespace: dapreshop spec: httpPipeline: handlers: - name: githubauth type: middleware.http.oauth2
接着我們在eshop-sample上創建一個鑒權服務並創建一個service,該service主要是獲取到“myauth”之后向github發起請求訪問其user接口獲取之前授權訪問者的基本用戶信息用於創建默認的商城管理員。獲取信息后會將user信息打包到cookie並通過302的方式回寫到admin.dapreshop.com方便創建用戶。
[RemoteService("oauthservice", "github", "github授權服務")] public interface IService { [RemoteFunc(funcDescription: "請求OAUTH登錄")] Task<Model> GetUserInfo(); } public class Service: IService { private readonly IHttpClientFactory httpClientFactory; public Service(IHttpClientFactory httpClientFactory) { this.httpClientFactory = httpClientFactory; } public async Task<Model> GetUserInfo() { var model = new Model() { login = "" }; if (HttpContextExt.Current.Headers.Any(x => x.Key.ToLower().Equals("myauth"))) { var req = new HttpRequestMessage(); req.Headers.Add("User-Agent", "dapr-eshop"); req.Headers.Add("Authorization", HttpContextExt.Current.Headers.FirstOrDefault(x => x.Key.ToLower().Equals("myauth")).Value); req.Method = HttpMethod.Get; req.RequestUri = new Uri("https://api.github.com/user"); var result = await httpClientFactory.CreateClient().SendAsync(req); if (result.IsSuccessStatusCode) { var content = await result.Content.ReadAsStringAsync(); HttpContextExt.Current.Response.Cookies.Append("githubuser", JsonSerializer.Serialize(JsonSerializer.Deserialize<Model>(content)), new Microsoft.AspNetCore.Http.CookieOptions() { Domain = "dapreshop.com" }); HttpContextExt.Current.Response.Redirect("http://admin.dapreshop.com:30882"); } } return model; } }
接着我們改造一下AccountUseCaseService的InitRoleBasedAccessControler這個方法,如果獲取到從頁面回調的cookie,則直接用cookie創建初始管理員,否則用默認值創建初始管理員(代碼略,具體看github對應的repo)
由於oauth會涉及到多次302重定向,我之前預設的簡易反代網關暫時走不通這個邏輯,所以這里我們直接將授權服務的dapr service暴露到ingress:(補充一個小知識,所有開啟了dapr的應用都會創建一個“你的應用名-dapr”的service,通過該service可以直接訪問sidecar)
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: namespace: dapreshop name: oauth annotations: kubernetes.io/ingress.class: "nginx" nginx.ingress.kubernetes.io/enable-cors: "true" nginx.ingress.kubernetes.io/cors-allow-origin: 'http://admin.dapreshop.com:30882' nginx.ingress.kubernetes.io/cors-allow-headers: 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authentication,AuthIgnore' spec: rules: - host: oauth.dapreshop.com http: paths: - path: / pathType: Prefix backend: service: name: oauthservice-dapr port: number: 80
照例將127.0.0.1 oauth.dapreshop.com 錄入host文件。接着我們回到github應用,將回調地址錄入:http://oauth.dapreshop.com:30882/v1.0/invoke/oauthservice/method/github/GetUser 保存
最后我們在admin.dapreshop.com的前端頁面增加一個跳轉到github的圖標,並將地址設置為“http://oauth.dapreshop.com:30882/v1.0/invoke/oauthservice/method/github/GetUser”,這樣點擊時即可進行oauth鑒權校驗:
一切就緒,啟動我們的電商demo,進入admin.dapreshop.com后,取消點擊初始化,點擊github小圖標,會跳轉到github授權頁面
登錄后會回跳到我們的oauth服務的GetUserInfo方法,並通過該方法拿到user並回寫到cookie中,此時再點擊初始化,則會根據github賬號創建對應的超管
整個流程就完畢了,大家可以clone最新的demo並嘗試一下~ 新增的幾個配置在Oxygen-Dapr.EshopSample\Deploy\middleware文件夾中