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

a1010發表於2021-05-06

  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授權
附錄:(如果你覺得對你有用,請給個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資料夾中

相關文章