【问题标题】:JWT Authentication How to verify http requests in a separate API project not the AuthServer projectJWT 身份验证如何在单独的 API 项目而不是 AuthServer 项目中验证 http 请求
【发布时间】:2019-09-03 11:20:20
【问题描述】:

看了几篇文章,尤其是this

我制作了自己的 ASP.NET Core 解决方案

AuthenticationAuthorisation 的 1 个项目(AuthServer),以及

1 个项目 (WebApi) 用于我的整个项目中的其余 API。

问题是: 如何在我的 WebApi 项目中验证 http 请求?

我知道一旦用户通过身份验证,客户端将持有令牌,对于后续请求,他们都需要传递令牌,在服务器端,它以某种方式通过这段代码验证这些请求AuthServer 项目的 Startup.cs:

services.AddAuthentication(x =>
        {
            x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        })
        .AddJwtBearer(x=> {
            x.Events = new JwtBearerEvents
            {
                OnTokenValidated = context =>
                {
                    var userService = context.HttpContext.RequestServices.GetRequiredService<IUserService>();
                    var userId = context.Principal.Identity.Name;
                    var user = userService.GetById(userId);
                    if(user == null)
                    {
                        context.Fail("Unauthorized");
                    }
                    return Task.CompletedTask;
                }
            };
            x.RequireHttpsMetadata = false;
            x.SaveToken = true;
            x.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(key),
                ValidateIssuer = false,
                ValidateAudience = false
            };
            
        });

但是对于 WebApi 项目,我需要做什么来验证令牌? 我想这不仅仅是在控制器上放置注释([Authorize])或类似的操作:

[Authorize]
[Route("api/[controller]")]
[ApiController]
public class ProductsController : ControllerBase
{ ....}

那我应该怎么做来验证我的 WebApi 项目中的令牌呢? 每次有请求进来时调用我的AuthServer项目中的Authenticate端点,然后执行WebApi中的代码?

【问题讨论】:

  • 通常您会先让客户端调用您的身份验证 API,从 Authenticate 端点获取令牌,然后客户端会在任何时候将该令牌作为标头值(不记名令牌)包含在请求中转到您的 WebApi 请求。我认为,如果您使用 Google 搜索任何类型的“JWT ASP.NET Core”,您应该找到有关如何在 WebApi 端查找传入身份验证令牌的示例。
  • 嗨@BenKrueger 感谢您的回复。我又找了一遍,所有的文章还是把 AuthServer 和 WebApi 项目的实现都说成一个项目。
  • @Franva 看来您可能想要运行 2 个单独的 ASP.NET 应用程序,一个处理授权,第二个处理剩余逻辑?
  • @Andriy 是的。这是我看了很多文章后的印象。能否请你帮忙?谢谢
  • 我建议您查看IdentityServer。使用它,您可以设置适当的身份验证提供程序(作为单独的服务器)和安全的 API 服务器,然后您可以使用经过身份验证的服务器。 quickstarts documentation 也将涵盖您的情况。

标签: c# asp.net-web-api asp.net-core jwt


【解决方案1】:

我假设您要运行 2 个单独的 ASP.NET 应用程序。 您可以通过向您的AuthServer 发送http 请求来验证来自WebApi 的请求。 您可以创建一个自定义属性来完成这项工作。 在 WebApi 项目中:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Primitives;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Security.Claims;
using System.Threading.Tasks;

namespace YourNamespace
{
    public class YourCustomAttribute : TypeFilterAttribute
    { 
        public YourCustomAuthAttribute(
            : base(typeof(AuthFilter))
        {
            Arguments = new object[] {
               // arguments gets passed to AuthFilter contructor,

            };
        }
    }

    public class AuthFilter : IAsyncAuthorizationFilter
    {
        private static readonly HttpClient http = new HttpClient();

        public AuthFilter()
        {
        }

        //Change it to fit your logic
        public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
        {
            var authorizationHeader = context.HttpContext.Request.Headers["Authtorization"];
            if (authorizationHeader == StringValues.Empty)
            {
                context.Result = new UnauthorizedResult();
            }
            else
            {
                var response = await http.GetAsync(
                    "your AuthServer address/login/?token=" + authorizationHeader.ToString(),
                    HttpCompletionOption.ResponseHeadersRead //because we want only status code
                );
                if (response.StatusCode != System.Net.HttpStatusCode.OK)
                {
                    context.Result = new ForbidResult();
                }
            }
        }
    }
}

假设您在 AuthServer 项目中的 LoginController 中有以下端点

[HttpGet]
public IActionResult ValidateToken(string token)
{
   //your logic here
}

属性用法同[Authorize]

也请查看此链接(我使用了其中的一些代码)https://www.red-gate.com/simple-talk/dotnet/net-development/jwt-authentication-microservices-net/。 它展示了如何手动验证 Jwt 令牌。

您可能还需要在 AuthServer 项目中设置 CORS,以允许 WebApi 发出请求 Startup.cs:

public void ConfigureServices(IServiceCollection services)
        {
            services.AddCors(options =>
            {
                options.AddPolicy("AllowAllHeaders",
                      builder =>
                      {
                          builder.AllowAnyOrigin()
                                 .AllowAnyHeader()
                                 .AllowAnyMethod();
                      });
            });
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env, IServiceProvider serviceProvider)
        {
            app.UseCors("AllowAllHeaders");
        }

【讨论】:

  • 感谢 Andriy,我应该在哪个项目中创建此自定义属性? AuthServer 还是 WebApi?示例中使用的 YourCustomAttribute 在哪里?
  • @Franva,属性在WebApi项目中声明和使用
  • 我应该在哪个项目中创建这个自定义属性?感谢您更新答案,是的,我已经设置了 CORS :)
  • @Franva,嗯,在WebApi项目中创建一个属性类
【解决方案2】:

经过数小时的阅读,我发现一篇文章讨论是否将 AuthServer 与您的 API Server 分开。

在大型商业项目中,将它们分开肯定更好,但就我而言,这只是我的副业,所以我最终将它们一起构建以节省能源。

【讨论】:

    猜你喜欢
    • 2020-11-01
    • 2023-03-10
    • 2019-12-12
    • 2016-07-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多