簡體   English   中英

用戶登錄未使用OWIN承載令牌進行身份驗證

[英]User login not being authenticated using OWIN bearer tokens

我正在使用MVC應用程序。 登錄由Web API處理。

我面臨的問題是,當我點擊MVC應用程序中的“登錄”按鈕時,API正在生成令牌以及用戶信息。 但是我無法在視圖中顯示用戶信息。

以下代碼位於MVC App的AccountController

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model)
{
   string token = Token.GetToken(Token.GRANT_TYPE, model.Email, model.Password, Token.CLIENT_ID, Token.CLIENT_SECRET);

  //token has the appropriate data if I debug it

   if (!string.IsNullOrEmpty(token))
       return RedirectToAction("Index", "Home");

   return View(model);
}

然后在視圖中我有

@if (Request.IsAuthenticated)
{
  <p>@User.Identity.GetUserName()</p> //this line is always blank
}

API看起來像這樣

public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{

        var allowedOrigin = context.OwinContext.Get<string>("as:clientAllowedOrigin");

        if (allowedOrigin == null) allowedOrigin = "*";

        context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { allowedOrigin });

        using (AuthRepository _repo = new AuthRepository())
        {
            ApplicationUser user = await _repo.FindUser(context.UserName, context.Password);

            if (user == null)
            {
                context.SetError("invalid_grant", "The user name or password is incorrect.");
                return;
            }
        }

        var identity = new ClaimsIdentity(context.Options.AuthenticationType);

        identity.AddClaim(new Claim(ClaimTypes.Name, context.UserName));
        identity.AddClaim(new Claim(ClaimTypes.Role, "user"));
        identity.AddClaim(new Claim("sub", context.UserName));

        var props = new AuthenticationProperties(new Dictionary<string, string>
            {
                {
                    "as:client_id", (context.ClientId == null) ? string.Empty : context.ClientId
                },
                {
                    "userName", context.UserName
                },
                {
                    "email", context.UserName
                },
            });

        var ticket = new AuthenticationTicket(identity, props);
        context.Validated(ticket);
}

有人能告訴我為什么請求沒有被認證? 我錯過了什么

從你的例子中我看起來有些不對勁的事情


第一部分:您的登錄方法

慣例是使用GrantResourceOwnerCredentials作為端點( /api/token ),它接收憑證返回訪問令牌

按照慣例,此端點替換Login(LoginViewModel)方法。 顯然你不應該使用Login()方法,但我懷疑你是。

  • 如果您使用的是Login方法,它只返回原始的,未更改的View Cre Model with Credentials。 您的LoginViewModel類可能包含令牌屬性,但您沒有填充它。 因此,登錄方法會對您的用戶進行身份驗證,但不會對其進行授權,因為用戶永遠不會獲取其訪問令牌。
  • 您的GrantResourceOwnerCredentials方法確實返回令牌並填充聲明。 但是,您是否有任何客戶端邏輯來存儲訪問令牌並在每個請求中發送它?
  • 除非您的令牌采用JWT (Json Web Tokens)之類的格式,否則我懷疑取消加密令牌以訪問聲明(例如userName / email)將是一項重大挑戰。 這意味着,除非是JWT,否則您的客戶端從訪問令牌中提取聲明並不容易。

第二部分:有人可以告訴我為什么請求沒有被認證?

驗證。 但這不是表單身份驗證。 沒有Cookie。 當API返回訪問令牌時,Razor Calls to Identity將無法工作。

在典型的Forms Auth模型中:

憑證被發送和驗證(經過身份驗證)。 如果驗證成功,則用戶被授權(給定訪問權限),其客戶端cookie具有加密的訪問信息和聲明。 OWIN Middle-ware在每個請求上讀取Cookie並填充httpContext( IdentityhttpContext對象上的屬性。)

訪問令牌工作流程:

非常相似,除了,因為沒有Cookie,並且API和客戶端View之間沒有連接,而不是View Models中返回的數據。 httpContext將不只是在服務器端(網頁API),每個OWIN中間件讀取訪問令牌的時間來填充。

所以,剃刀召喚

@User.Identity.GetUserName()

會出現空洞。


解決方案:在客戶端上獲取並存儲用戶信息

如果您需要來自服務器的用戶信息,您應該在客戶端上緩存用戶名(以及您需要的任何其他信息)。

在客戶端瀏覽器上存儲用戶信息的方法

  • 會話存儲
  • 本地存儲
  • JavaScript單例類(如Angular服務)

獲取用戶名的方法

  • 存儲用戶輸入憑據時獲得的用戶名(如果身份驗證失敗,請清除它)

  • 有一個專用的終點(API方法)來返回您想要的用戶信息

  • 退回JWT的索賠。

如果您更改令牌類型(在Global.asax或Startup.cs中 - 取決於您配置的方式)以使用Jason Web Tokens ,客戶端將能夠取消您的令牌編碼並將聲明作為JSON數組讀取。


  • 最后一個選項:您可以同時使用訪問令牌和Cookie。 您可以返回訪問令牌並創建cookie。 在配置Web API時,為Web API禁止cookie auth。

  • 最后的想法:訪問令牌用於額外的安全級別(cookie更容易受到攻擊)。 但是您使用Access Tokens的目的是什么? 如果您正在創建與AngularJS類似的SPA (單頁應用程序),則此類安全性更為重要。 否則,Cookie Auth是一個更簡單的工作流程,除非您覺得需要額外的安全性,否則Cookie更可取。

獲得了令牌,但未加載主體。 在控制器實例化之前的某個時間,您必須將主體加載到線程上。 如果您嘗試將其設置在控制器中,則不會反映新數據,因為控制器數據和視圖同時呈現,並且包括主體。

由於存在重定向,您可以將其用作加載它的機會。 為了實現這一點,您必須將令牌保存到cookie或會話中,以便在下一個請求(重定向)時可以使用它,記住響應必須使其返回到瀏覽器為了實際存儲cookie,后續重定向將包含剛剛保存的cookie。 然后在控制器解析之前插入管道(就像在自定義的http模塊中一樣),將其拉出來,使用它來構建主體並將其設置在線程上,它將在請求期間出現。

我還建議切換到使用JWT令牌。 一旦你學會了如何制作它們,它們就更有用,並包含更多有用的信息......你在索賠中放置的任何東西,它們都會直接反序列化為ClaimsIdentity。

或者,您可以簡單地將令牌保存到auth票證cookie並配置OWIN以在MVC端選擇它並為您構建主體...基本上做我剛剛為您建議的所有內容。 我不熟悉它,所以我不確定這是否有用。

以下是基本流程的樣子。 紅色部分是我認為你缺少的部分。 橙色部分也缺失了,但您可以通過自定義HttpModule手動完成,也可以配置OWIN為您完成(我認為)。

在此輸入圖像描述

你必須處理客戶端和服務器登錄(客戶端是webapp調用api和服務器是api)

正如@Dave所提到的,您需要在客戶端使用中間件來存儲令牌。

對於一個真正的Restfull api,你將需要存儲所有信息客戶端(仍然是webapp而不是用戶),而不是api端。

我的方法是添加一個所有其他控制器都將繼承的基本控制器。

在Session中處理用戶信息的位置,在登錄時,您存儲令牌並使用自定義UserManager / SigninManager和您自己的Identity實現來管理用戶連接。

這個過程的有用鏈接:

MVC API安全個人帳戶

暫無
暫無

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

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