asp.net core 外部認證多站點模式實現

来源:https://www.cnblogs.com/passingwind/archive/2018/08/21/9511022.html
-Advertisement-
Play Games

PS:之前因為需要擴展了微信和QQ的認證,使得網站是可以使用QQ和微信直接登錄。github 傳送門 。然後有小伙伴問,能否讓這個配置信息(appid, appsecret)按需改變,而不是在 ConfigureServices 裡面寫好。 先上 官方文檔 : https://docs.micros ...


PS:之前因為需要擴展了微信和QQ的認證,使得網站是可以使用QQ和微信直接登錄。github 傳送門 。然後有小伙伴問,能否讓這個配置信息(appid, appsecret)按需改變,而不是在 ConfigureServices  裡面寫好。

先上 官方文檔 :  https://docs.microsoft.com/zh-cn/aspnet/core/security/authentication/social/?view=aspnetcore-2.1 

官方已經實現了 microsft,facebook,twitter,google 等這幾個網站認證。代碼可以認證授權庫看到找到 https://github.com/aspnet/Security  。

國內的QQ和微信其實也是基於OAuth來實現的,所以自己集成還是比較容易。

正常情況下,配置這個外部認證都是在 ConfigureServices 裡面配置好,並且使用配置或者是使用機密文件的形式來保存 appid 等信息。

回到正文,多站點模式,就是一個網站下分為多個子站點,並且不同的子站點可以配置不同的appId 。Asp.net core 預設的配置模式,在這種場景下已經適應不了了。

先上代碼: https://github.com/jxnkwlp/AspNetCore.AuthenticationQQ-WebChat/tree/muti-site

官方代碼分析:

1,RemoteAuthenticationHandler  遠程認證處理程式。位於 microsoft.aspnetcore.authentication  下 。 源碼 (https://github.com/aspnet/Security/blob/master/src/Microsoft.AspNetCore.Authentication/RemoteAuthenticationHandler.cs)

這個是泛型類,並且需要一個  TOptions ,這個 TOptions 必須是繼承 RemoteAuthenticationOptions 的類。

 

2,OAuthHandler 實現 OAuth 認證處理程式,這個類繼承 RemoteAuthenticationHandler 。同時必須實現一個 OAuthOptions 。

正常情況下實現 QQ、微信、github ,google ,facebook 等登錄都是基於這個來實現的。 OAuthHandler 已經實現了標準的 OAuth 認證。

源碼:https://github.com/aspnet/Security/blob/master/src/Microsoft.AspNetCore.Authentication.OAuth/OAuthHandler.cs

在 ConfigureServices 中,使用  AddFacebook 等方法,就是將 對於的 Handler 添加到 處理管道中,這些管到都是實現了 OAuth,然後傳遞 對應的 Options 來配置Handler 。

 

3,回到Account/ExternalLogin ,在提交外部登錄的請求中, AuthenticationProperties  properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl);  //這行代碼的作用是 配置當前外部登錄返回URL和認證的相關屬性。return Challenge(properties, provider);  // 將結果轉到相關相關處理程式。這裡返回的結果用於上面  OAuthHandler 作為一個處理參數。從這開始,就進入了 OAuthHandler 的處理範圍了。

 

4,查看 OAuthHandler 代碼 。  Task HandleChallengeAsync(AuthenticationProperties properties);  這個函數作為接收上一步中傳遞的 認證參數。   預設實現代碼:

protected override async Task HandleChallengeAsync(AuthenticationProperties properties) 
{

    if (string.IsNullOrEmpty(properties.RedirectUri)) 
    { 
        properties.RedirectUri = CurrentUri; 
    }

    // OAuth2 10.12 CSRF

    GenerateCorrelationId(properties);

    var authorizationEndpoint = BuildChallengeUrl(properties, BuildRedirectUri(Options.CallbackPath));

    var redirectContext = new RedirectContext<OAuthOptions>(

        Context, Scheme, Options,

        properties, authorizationEndpoint);

    await Events.RedirectToAuthorizationEndpoint(redirectContext); 
}
protected virtual string BuildChallengeUrl(AuthenticationProperties properties, string redirectUri)
{
    var scopeParameter = properties.GetParameter<ICollection<string>>(OAuthChallengeProperties.ScopeKey);
    var scope = scopeParameter != null ? FormatScope(scopeParameter) : FormatScope();

    var state = Options.StateDataFormat.Protect(properties);
    var parameters = new Dictionary<string, string>
    {
        { "client_id", Options.ClientId },
        { "scope", scope },
        { "response_type", "code" },
        { "redirect_uri", redirectUri },
        { "state", state },
    };

    return QueryHelpers.AddQueryString(Options.AuthorizationEndpoint, parameters);
}

 

在這裡面,構建了一個請求URL, 要求的這個URL 是目標站點授權的URL, 比如微信的那個黑色背景中間有二維碼的頁面。  這個構建請求URL的方法可以重寫。

5,在上一步中,在需要授權的網站,授權完成後,會跳轉到自己的網站並且帶上授權相關數據。入口是  Task<HandleRequestResult> HandleRemoteAuthenticateAsync();  

改造方法:

在上面的分析中,官方的實現是 在 ConfigureServices 中配置好參數 TOptions ,然後在 Handler 中 獲取該參數。我們的目的是在請求中可以按需改變參數,如 client_id。

1,定義一個介面 IClientStore 和 一個實體 ClientStoreModel 。

public interface IClientStore
{
    /// <summary>
    ///<paramref name="provider"/><paramref name="subjectId"/> 查找 <seealso cref="ClientStoreModel"/>
    /// </summary> 
    ClientStoreModel FindBySubjectId(string provider, string subjectId);
}

 

/// <summary>
///  表示一個 Client 信息 
/// </summary>
public class ClientStoreModel
{
    public string Provider { get; set; }

    public string SubjectId { get; set; }

    /// <summary>
    /// Gets or sets the provider-assigned client id.
    /// </summary>
    public string ClientId { get; set; }

    /// <summary>
    /// Gets or sets the provider-assigned client secret.
    /// </summary>
    public string ClientSecret { get; set; }

}

 

IClientStore 用於查找 client 的配置信息

2,在 Account/ExternalLogin 中,新增一個 參數 subjectId  ,表示在當前某個認證(Provider)中是哪個請求(SubjectId) 。

同時在返回的授權配置參數中將subjectId 保存起來。

 

3,定義一個 MultiOAuthHandler ,集成 RemoteAuthenticationHandler  ,不繼承  OAuthHandler 是因為 這裡需要一個新的 Options.  (完整代碼 請看代碼倉庫)  定義: class MultiOAuthHandler<TMultiOAuthOptions>:RemoteAuthenticationHandler<TMultiOAuthOptions>whereTMultiOAuthOptions:MultiOAuthOptions,new() 

在構造函數中添加參數 IClientStore 。

4,在預設的實現中,從外部授權網站跳轉回自己的網站的時候,預設的路徑是 /signin-{provider} , 比如 /signin-microsoft  。為了區分請求的 subjectId ,  這個預設路徑將改為  /signin-{provider}/subject/{subjectId}  。

5,修改 HandleRemoteAuthenticateAsync  ,在開頭添加2行代碼,用於獲取 subjectId 。

var callbackPath = Options.CallbackPath.Add("/subject").Value;

var subjectId = Request.Path.Value.Remove(0, callbackPath.Length + 1);

 

6,修改 ExchangeCodeAsync 方法

protected virtual async Task<OAuthTokenResponse> ExchangeCodeAsync(string subjectId, string code, string redirectUri)
{
    var clientStore = GetClientStore(subjectId);

    var tokenRequestParameters = new Dictionary<string, string>()
    {
        { "client_id", clientStore.ClientId },
        { "client_secret", clientStore.ClientSecret },

        { "redirect_uri", redirectUri },
        { "code", code },
        { "grant_type", "authorization_code" },
    };

    var requestContent = new FormUrlEncodedContent(tokenRequestParameters);

    var requestMessage = new HttpRequestMessage(HttpMethod.Post, Options.TokenEndpoint);
    requestMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    requestMessage.Content = requestContent;
    var response = await Backchannel.SendAsync(requestMessage, Context.RequestAborted);
    if (response.IsSuccessStatusCode)
    {
        var payload = JObject.Parse(await response.Content.ReadAsStringAsync());
        return OAuthTokenResponse.Success(payload);
    }
    else
    {
        var error = "OAuth token endpoint failure: " + await Display(response);
        return OAuthTokenResponse.Failed(new Exception(error));
    }
}

 

7,還有一些小修改,就不一一列出來了。  到這裡  MultiOAuthHandler  相關就調整好了。

我把這個單獨出來了  Microsoft.AspNetCore.Authentication.MultiOAuth 

 

8,使用 。 實現 IClientStore 介面,然後在 ConfigureServices  中添加如下代碼:

services.AddAuthentication()
    .AddMultiOAuthStore<MylientStore>() 
    .AddMultiWeixinAuthentication(); // 微信

 

9, 目前github 上的demo 只對 微信  做了實現。

 

PS:如有錯誤,歡迎指正。

 

源地址: https://blog.wuliping.cn/post/aspnet-core-security-authentication-social-multi-config 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Wtf(暫時命名,隨便起的 = _=),模仿WPF的框架,還沒有完善,只有簡單的基礎元素,支持數據綁定。雖然支持mono但是mono有bug 寫這個只是興趣愛好,感覺也沒多大意義了,如果這個UI框架完善了,有多少人願意用?畢竟Windows上有WPF,而且C#跨平臺需求也不多啊。我對WPF也不算熟悉 ...
  • 冒泡排序的運行原理(好理解): 備註:上述講解來自 維基百科 冒泡排序 代碼如下(從大到小排序): ...
  • 問題抽象:當某一資源同一時刻允許一定數量的線程使用的時候,需要有個機制來阻塞多餘的線程,直到資源再次變得可用。線程同步方案:Semaphore、SemaphoreSlim、CountdownEvent方案特性:限量供應;除所有者外,其他人無條件等待;先到先得,沒有先後順序 1、Semaphore類 ...
  • 使用場景 最近用 .net core mvc 寫了一個工具類的項目,作為我們項目的後臺管理網站使用。第一次被老大拿去部署的時候被告知不可用,同樣的代碼在我電腦和我的iis上都可以使用的啊。 後來才知道,原來老大是把這個項目作為某一個項目的應用程式發佈上去了,在使用過程中會有一個目錄問題。 解決方案一 ...
  • /// <summary> /// 根據條件,使用存儲過程分頁查詢電影 /// </summary> /// <param name="name"></param> /// <param name="time"></param> /// <param name="size"></param> /// ...
  • 一、前言 開發環境: 部署環境 ASP.NET Core 示例項目 項目創建完成後,需要修改Program.cs文件手動指定啟動的Url為:http://*:5000 http://*:5000 可以相容 http://localhost:5000,http://127.0.0.1:5000,htt ...
  • ASP.NET Core的實時庫: SignalR -- 預備知識 ...
  • 記憶體映射數據處理類主要函數及變數如下: 科學數據結構體定義如下: 圖像數據結構體如下: ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...