通過 Dapr 實現一個簡單的基於 dotnet 的微服務電商系統——一步一步教你如何擼 Dapr 之 OAuth2 授權

Oauth2 授權,熟悉微信開發的同學對這個東西應該不陌生吧。當我們的應用系統需要集成第三方授權時一般都會做 oauth 集成,今天就來看看在 Dapr 的語境下我們如何僅通過配置無需修改應用程序的方式讓第三方服務保護我們的 API 應用。

目錄:

一、通過 Dapr 實現一個簡單的基於. net 的微服務電商系統

二、通過 Dapr 實現一個簡單的基於. net 的微服務電商系統 (二)——通訊框架講解

三、通過 Dapr 實現一個簡單的基於. net 的微服務電商系統 (三)——一步一步教你如何擼 Dapr

四、通過 Dapr 實現一個簡單的基於. net 的微服務電商系統 (四)——一步一步教你如何擼 Dapr 之訂閱發佈

五、通過 Dapr 實現一個簡單的基於. net 的微服務電商系統 (五)——一步一步教你如何擼 Dapr 之狀態管理

六、通過 Dapr 實現一個簡單的基於. net 的微服務電商系統 (六)——一步一步教你如何擼 Dapr 之 Actor 服務

[七、通過 Dapr 實現一個簡單的基於. net 的微服務電商系統 (七)——一步一步教你如何擼 Dapr 之服務限流]](https://www.readfog.com/a/1634023379212275712)

八、通過 Dapr 實現一個簡單的基於. net 的微服務電商系統 (八)——一步一步教你如何擼 Dapr 之鏈路追蹤

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 文件夾中

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/6mEYT6zr8qy3j56xk059JA