簡體   English   中英

具有自定義JWT身份驗證的OAuth

[英]OAuth with custom JWT authentication

我正在努力用OAuth和JWT實現自定義身份驗證流程。 基本上它應該如下:

  • 用戶點擊登錄
  • 用戶重定向到第三方OAuth登錄頁面
  • 用戶登錄頁面
  • 我得到access_token並請求用戶信息
  • 我獲取用戶信息並創建自己的JWT令牌來回發送

我一直在關注如何構建OAuth身份驗證的這個很棒的教程 ,唯一不同的部分是Jerrie正在使用Cookies

到目前為止我做了什么:

配置AuthenticationService

services.AddAuthentication(options => 
{
    options.DefaultChallengeScheme = "3rdPartyOAuth";
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie() // Added only because of the DefaultSignInScheme
.AddJwtBearer(options =>
{
    options.TokenValidationParameters = // Ommited for brevity
})
.AddOAuth("3rdPartyOAuth", options =>
{
    options.ClientId = securityConfig.ClientId;
    options.ClientSecret = securityConfig.ClientSecret;
    options.CallbackPath = new PathString("/auth/oauthCallback");

    options.AuthorizationEndpoint = securityConfig.AuthorizationEndpoint;
    options.TokenEndpoint = securityConfig.TokenEndpoint;
    options.UserInformationEndpoint = securityConfig.UserInfoEndpoint;

    // Only this for testing for now
    options.ClaimActions.MapJsonKey("sub", "sub");

    options.Events = new OAuthEvents
    {
        OnCreatingTicket = async context =>
        {
            // Request for user information
            var request = new HttpRequestMessage(HttpMethod.Get, context.Options.UserInformationEndpoint);
            request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", context.AccessToken);

            var response = await context.Backchannel.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, context.HttpContext.RequestAborted);
            response.EnsureSuccessStatusCode();

            var user = JObject.Parse(await response.Content.ReadAsStringAsync());

            context.RunClaimActions(user);
        }
    };
});

Auth控制器

    [AllowAnonymous]
    [HttpGet("login")]
    public IActionResult LoginIam(string returnUrl = "/auth/loginCallback")
    {
        return Challenge(new AuthenticationProperties() {RedirectUri = returnUrl});
    }

    [AllowAnonymous]
    [DisableRequestSizeLimit]
    [HttpGet("loginCallback")]
    public IActionResult IamCallback()
    {
        // Here is where I expect to get the user info, create my JWT and send it back to the client
        return Ok();
    }

免責聲明:此OAuth流程現已納入。 我有一個創建和使用我自己的JWT工作和一切的流程。 我不會在這里發帖,因為我的問題就在此之前。

我想要的是

在Jerrie的帖子中,您可以看到他設置了DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme; 有了它,當達到/auth/loginCallback時,我在HttpContext有用戶聲明。 問題是我的DefaultAuthenticateScheme設置為JwtBearersDefaultloginCallback叫我不能看到用戶無處索賠的Request 在這種情況下,如何在回調中訪問OnCreatingTicketEvent上獲得的信息?

獎金問題:我對OAuth了解不多(現在確定很清楚)。 您可能已經注意到我的options.CallbackPathlogin端點上的Challenge中傳遞的RedirectUri不同。 我希望第三部分OAuth提供程序可以調用option.CallbackPath ,但這不會發生(顯然)。 我必須將CallbackPath設置為我在OAuth提供程序配置中設置的相同值(如使用GitHub的Jerries教程)才能工作。 是對的嗎? Callback只用於匹配配置嗎? 我甚至可以評論端點CallbackPath指向它並繼續以相同的方式工作......

謝謝!

改變[AllowAnonymous]

[Authorize]

'loginCallback'端點( AuthController.IamCallback方法)

驗證

正如Jerrie在帖子中所說的那樣,對auth中間件有一個很好的解釋: https//digitalmccullough.com/posts/aspnetcore-auth-system-demystified.html

您可以在“ 身份驗證和授權流 ”部分中查看流程圖

第二步是身份驗證中間件調用默認處理程序的身份驗證

由於您的默認身份驗證處理程序是Jwt,因此在oauth流之后上下文不會被用戶數據限制,因為它使用CookieAuthenticationDefaults.AuthenticationScheme

嘗試:

[AllowAnonymous]
[DisableRequestSizeLimit]
[HttpGet("loginCallback")]
public IActionResult IamCallback()
{
    //
    // Read external identity from the temporary cookie
    //
    var result = await HttpContext.AuthenticateAsync(CookieAuthenticationDefaults.AuthenticationScheme);

    if (result?.Succeeded != true)
    {
        throw new Exception("Nein");
    }

    var oauthUser = result.Principal;

    ...

    return Ok();
}

偉大的方案摘要: ASP.NET Core 2 AuthenticationSchemes

您可以使用https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.authentication.authenticationhttpcontextextensions.signinasync?view=aspnetcore-2.2來保留您的用戶

獎金

我必須將CallbackPath設置為我在OAuth提供程序配置中設置的相同值(如使用GitHub的Jerries教程)才能工作。 是對的嗎?”

是。 出於安全原因,注冊的回調uri(在授權服務器上)和提供的回調uri(由客戶端發送)必須匹配。 因此您無法隨機更改它,或者如果您更改它,您也必須在auth服務器上更改它。

如果沒有此限制,那么帶有mailformed鏈接(帶有修改后的回調網址)的電子郵件可以獲得授權。 這稱為Open Redirect,rfc也引用它: https//tools.ietf.org/html/rfc6749#section-10.15

OWASP有一個很好的描述: https//github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md

我甚至可以評論端點CallbackPath指向並繼續以相同的方式工作......“

這是因為您的客戶端是可信任的(您提供了您的秘密,而且您不是一個完全正面的單頁應用程序)。 因此,您可以選擇發送回調uri。 但是如果你發送它,它必須與服務器上注冊的那個匹配。 如果您不發送它,auth服務器將重定向到其側面注冊的URL。

https://tools.ietf.org/html/rfc6749#section-4.1.1

redirect_uri可選。 如3.1.2節所述。

https://tools.ietf.org/html/rfc6749#section-3.1.2

授權服務器在客戶端注冊過程中或在發出授權請求時,將用戶代理重定向到先前使用授權服務器建立的客戶端重定向端點。

https://tools.ietf.org/html/rfc6749#section-3.1.2.2

授權服務器必須要求以下客戶端注冊其重定向端點:

  • 公共客戶。
  • 機密客戶端使用隱式授權類型。

您的客戶是保密的,並使用授權代碼授予類型( https://tools.ietf.org/html/rfc6749#section-1.3.1

https://tools.ietf.org/html/rfc6749#section-3.1.2.3

如果已注冊了多個重定向URI,如果只注冊了部分重定向URI,或者沒有注冊重定向URI,則客戶端必須使用“redirect_uri”請求參數包含帶有授權請求的重定向URI。

您已注冊重定向uri,這就是auth服務器不會引發錯誤的原因。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM