【问题标题】:ASP.Net Core MVC/API/SignalR - Change authentication schemes (Cookie & JWT)ASP.Net Core MVC/API/SignalR - 更改身份验证方案(Cookie 和 JWT)
【发布时间】:2019-05-25 00:28:02
【问题描述】:

我有一个 .Net Core 2.2 Web 应用程序 MVC,我在其中添加了 API 控制器和 SignalR 集线器。另一方面,我有一个调用集线器方法的移动应用程序。在从应用程序调用集线器之前,我通过 API 调用验证我的用户 - 获取 JWT 令牌 - 并将此令牌用于未来的请求,这样我可以在我的集线器方法中使用 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
        [...]

然后使用令牌:

_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 Web 应用程序不再按预期工作,因为它无法在请求中获取当前经过身份验证的用户。

删除行:

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

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

我一直在搜索如何处理不同的方案(在我的情况下是 cookie + jwt),据我了解,这在设计上已经不可能了。

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

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

提前致谢。

【问题讨论】:

  • 在 web 应用中实现 jwt auth 有问题吗?
  • DefaultAuthenticateScheme 设置为 JWT 时,Web 应用无法识别用户。

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


【解决方案1】:

有多种方法可以解决您遇到的问题,但首先让我们了解一下为什么它目前不起作用。

DefaultAuthenticateScheme 是什么意思

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

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

授权系统默认策略

如果您的应用程序的所有受保护端点都可供通过 cookie 或 JWT 身份验证的客户端访问,则一种选择是使用授权系统默认策略。当您使用 AuthorizeAttribute 类的“空”实例时,将使用该特殊策略 - 作为装饰控制器/操作的属性,或在应用程序级别全局使用 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 = "&lt;policy-name&gt;")] 装饰它们来在适当的端点中引用这些策略。附带说明一下,如果您的策略之间的唯一区别是身份验证方案,则无需创建策略并使用 AuthenticationSchemes 属性在 [Authorize] 属性中引用适当的身份验证方案即可获得相同的结果。

当您有更复杂的规则时,策略很有价值,例如特定声明需要这个特定值

我希望这会有所帮助,让我知道你的进展! ?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-09-02
    • 2020-10-09
    • 1970-01-01
    • 2018-01-28
    • 1970-01-01
    • 2020-07-27
    • 2021-08-27
    • 2018-02-23
    相关资源
    最近更新 更多