c# - ASP.Net Core MVC/API/SignalR - 更改身份验证方案(Cookie 和 JWT)

标签 c# authentication asp.net-core-mvc jwt asp.net-core-2.2

我有一个 .Net Core 2.2 Web 应用程序 MVC,我在其中添加了 API Controller 和 SignalR 集线器。另一方面,我有一个调用集线器方法的移动应用程序。在从应用程序调用集线器之前,我通过 API 调用对我的用户进行身份验证 - 取回 JWT token - 并将此 token 用于 future 的请求,这样我就可以使用 Context.User.Identity.Name在我的中心方法中:

public static async Task<string> GetValidToken(string userName, string password)
{
   using (var client = new HttpClient())
   {
     client.BaseAddress = new Uri(_API_BASE_URI);
     client.DefaultRequestHeaders.Accept.Clear();
     client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

     LoginViewModel loginVM = new LoginViewModel() { Email = userName, Password = password, RememberMe = false };
     var formContent = Newtonsoft.Json.JsonConvert.SerializeObject(loginVM);
     var content = new StringContent(formContent, Encoding.UTF8, "application/json");
     HttpResponseMessage responseMessage;
     try
     {
        responseMessage = await client.PostAsync("/api/user/authenticate", content);
        var responseJson = await responseMessage.Content.ReadAsStringAsync().ConfigureAwait(false); ;
        var jObject = JObject.Parse(responseJson);
        _TOKEN = jObject.GetValue("token").ToString();
        return _TOKEN;
     }catch
        [...]

然后使用 token :

_connection = new HubConnectionBuilder().WithUrl(ApiCommunication._API_BASE_URI + "/network", options =>
{
  options.AccessTokenProvider = () => Task.FromResult(token);
}).Build();

到目前为止一切顺利。它在我的移动应用程序上按预期工作。但为了让它工作,我必须在服务器端设置这段代码 (Startup.cs):

services.AddAuthentication(options =>
{
   options .DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
   options .DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
 })
 .AddJwtBearer(x =>
 {
    x.Events = new JwtBearerEvents
    {
        OnMessageReceived = context =>
        {
            ...

这使我无法再使用 cookie 身份验证,因此 mvc 网络应用程序不再按预期工作,因为它无法在请求中获取当前经过身份验证的用户。

删除行:

options .DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options .DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;

使网络应用程序正常工作,但不再是移动应用程序(由于 Context.User.Identity.Name 等于 null,集线器调用失败)。

我一直在四处寻找如何处理不同的方案(在我的例子中是 cookie + jwt),据我所知,这在设计上是不可能的了。

是否有任何可能的解决方法来使用双重方案,或者我是否遗漏了什么?

我想也许我应该托管 2 个独立的项目,一个使用 Cookie 身份验证,另一个使用 JWT?

提前致谢。

最佳答案

有多种方法可以解决您遇到的问题,但首先让我们了解一下它目前无法正常工作的原因。

什么DefaultAuthenticateScheme意味着

当您为 DefaultAuthenticateScheme 设置一个值时AuthenticationOptions的属性(property),您指示身份验证中间件尝试针对该特定方案对每个 HTTP 请求进行身份验证。我将假设您正在使用 ASP.NET Identity 进行基于 cookie 的身份验证,并且当您调用 AddIdentity 时,它将cookie认证方案注册为默认认证方案;你可以在 source code on GitHub 中看到这个.

但是,这并不意味着您不能在您的应用程序中使用任何其他身份验证方案。

授权系统默认策略

如果您的应用程序的所有 protected 端点都可以被使用 cookie 或 JWT 进行身份验证的客户端访问,一种选择是使用授权系统默认策略。当您使用 AuthorizeAttribute 的“空”实例时,将使用该特殊策略类——作为装饰 Controller / Action 的属性,或者在应用程序级别全局使用 new AuthorizeFilter(new AuthorizeAttribute()) .

默认策略设置为只需要经过身份验证的用户,但没有定义需要“尝试”哪些身份验证方案来验证请求。结果是它依赖于已经执行的身份验证过程。它解释了您遇到的行为,其中一次只有 2 个方案中的一个起作用。

我们可以用一些代码更改默认策略:

services.AddAuthorization(options =>
{
    options.DefaultPolicy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .AddAuthenticationSchemes("<your-cookie-authentication-scheme", "your-jwt-authentication-scheme")
        .Build();
})

具体授权政策

如果您发现自己需要某些端点只能由使用 cookie 进行身份验证的客户端访问,而其他使用 JWT 的客户端可以访问,则可以利用授权策略。

它们的工作方式与默认策略完全相同,希望您可以根据端点选择适用的策略。您可以像这样添加策略:

services.AddAuthorization(options =>
{
    options.AddPolicy("Cookies", new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .AddAuthenticationSchemes("<your-cookie-authentication-scheme")
        .Build());

    options.AddPolicy("JWT", new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .AddAuthenticationSchemes("<your-jwt-authentication-scheme")
        .Build());
})

然后,您可以通过使用 [Authorize(Policy = "<policy-name>")] 装饰它们来在适当的端点中引用这些策略。 .作为旁注,如果您的策略之间的唯一区别是身份验证方案,则可以在不创建策略并引用 [Authorize] 中的适当身份验证方案的情况下实现相同的结果。属性与 AuthenticationSchemes属性(property)。

当您有更复杂的规则时,政策很有值(value),例如,特定声明需要此特定值

希望这对您有所帮助,让我知道您的进展情况! 👍

关于c# - ASP.Net Core MVC/API/SignalR - 更改身份验证方案(Cookie 和 JWT),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53937191/

相关文章:

javascript - AJAX 表单提交不阻止默认操作

c# - 混合 C# 和 HTML Helper 标签 ASP.NET MVC 6 (ASP.NET Core)

asp.net - 如何将 Active Directory 用于 ASP.Net 5 (MVC6) Intranet 应用程序

c# - Asp.Net 5 TagHelper 模型状态绑定(bind)

c# - 我的 IsConnected 始终返回 true

php - PHP 中的 session 和登录混淆

c# - ASP.NET 5 身份 - 自定义 SignInManager

c# - EF Core 动态过滤器

c# - 为什么 try/finally block 的存在会阻止垃圾收集器工作?

azure - 验证我的 Azure 帐户会打开安全性无效的本地主机网页