【问题标题】:Authorization mechanism which uses JWT token OR API-key in .NET Core在 .NET Core 中使用 JWT 令牌或 API 密钥的授权机制
【发布时间】:2021-06-13 03:23:47
【问题描述】:

我是 .NET Core 3.1 的新手,我正在尝试创建一种授权机制,该机制将使用 JWT 令牌或 API 密钥。此机制将用于所有端点,除了将为登录机制提供服务的端点。我试图以here 所示的方式创建一个 API-key 属性并用它装饰所有控制器,但是,这仅在未设置 [Authorize] 属性时才有效。当我设置 [Authorize] 属性并在我的 API-key 属性中设置断点时,它将永远无法到达,并且我得到 401 Unauthorized 作为响应。有没有机会让两种授权方法并行工作?如果是这样,请指导我如何实现。

示例代码可以在here找到

【问题讨论】:

  • 请包含您尝试使用的代码的 sn-p
  • 欢迎来到 SO。您需要先缩小问题的范围:JWT 还是 API 密钥?由于您在谈论登录,我认为您正在寻找 JWT,因为 API 密钥通常不是用户身份验证的好选择(您的链接文章也解释了这一点)。选择后,请提供您尝试过的minimal reproducible example
  • @Xerillio JWT 供用户使用,API 密钥将用于授权第三方服务。

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


【解决方案1】:

我试图以此处显示的方式创建 API 密钥属性,并且 用它装饰所有控制器,但是,这只有在没有时才有效 [授权] 属性已设置。当我设置 [Authorize] 属性和 在我的 API-key 属性中设置一个断点,它永远不会到达并且 我收到 401 Unauthorized 作为响应。

问题涉及当使用自定义 API-Key 属性和 [Authorize] 属性一起使用时,控制器或操作方法将同时配置 JWT 身份验证和 API-Key 验证,在请求标头中,它应该包含JWT 令牌和 API 密钥。如果缺少其中任何一个,则会显示 401 Unauthorized 错误。

是否有机会同时使用两种授权方法 平行线?如果是这样,请指导我如何实现。

您的意思是使用任何一种授权方法,您可以访问相关的操作方法,如果是这种情况,您可以尝试使用自定义的授权属性。

例如:使用以下代码创建一个 CustomAuthorization:

[AttributeUsage(AttributeTargets.Class)]
public class CustomAuthorization : Attribute, IAuthorizationFilter
{ 
    /// <summary>  
    /// This will Authorize User  
    /// </summary>  
    /// <returns></returns>  
    public void OnAuthorization(AuthorizationFilterContext filterContext)
    {

        if (filterContext != null)
        {
            //get the authorization header
            Microsoft.Extensions.Primitives.StringValues authTokens;
            filterContext.HttpContext.Request.Headers.TryGetValue("Authorization", out authTokens);

            var _token = authTokens.FirstOrDefault();

            if (_token != null)
            {
                string authToken = _token;
                if (authToken != null)
                {
                    if (IsValidToken(authToken))
                    {
                        filterContext.HttpContext.Response.Headers.Add("Authorization", authToken);
                        filterContext.HttpContext.Response.Headers.Add("AuthStatus", "Authorized");

                        filterContext.HttpContext.Response.Headers.Add("storeAccessiblity", "Authorized");

                        return;
                    }
                    else
                    {
                        filterContext.HttpContext.Response.Headers.Add("Authorization", authToken);
                        filterContext.HttpContext.Response.Headers.Add("AuthStatus", "NotAuthorized");

                        filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
                        filterContext.HttpContext.Response.HttpContext.Features.Get<IHttpResponseFeature>().ReasonPhrase = "Not Authorized";
                        filterContext.Result = new JsonResult("NotAuthorized")
                        {
                            Value = new
                            {
                                Status = "Error",
                                Message = "Invalid Token"
                            },
                        };
                    }

                }

            }
            else
            {
                //if the request header doesn't contain the authorization header, try to get the API-Key.
                Microsoft.Extensions.Primitives.StringValues apikey;
                var key = filterContext.HttpContext.Request.Headers.TryGetValue("ApiKey", out apikey);
                var keyvalue = apikey.FirstOrDefault();

                //if the API-Key value is not null. validate the API-Key.
                if(keyvalue != null)
                {
                    filterContext.HttpContext.Response.Headers.Add("ApiKey", keyvalue);
                    filterContext.HttpContext.Response.Headers.Add("AuthStatus", "Authorized");

                    filterContext.HttpContext.Response.Headers.Add("storeAccessiblity", "Authorized");

                    return;
                }

                
                filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
                filterContext.HttpContext.Response.HttpContext.Features.Get<IHttpResponseFeature>().ReasonPhrase = "Please Provide authToken";
                filterContext.Result = new JsonResult("Please Provide auth Token")
                {
                    Value = new
                    {
                        Status = "Error",
                        Message = "Please Provide auth Token"
                    },
                };  
            }
        }
    }

    public bool IsValidToken(string authToken)
    {
        //validate Token here  
        return true;
    }
}

然后,在 API 控制器中使用上面的 CustomAuthorization:

[Route("api/[controller]")]
[ApiController]
//[Authorize]
//[ApiKey]
[CustomAuthorization]
public class ValuesController : ControllerBase
{
    // GET: api/<ValuesController>
    [HttpGet]
    public IEnumerable<string> Get()
    {
        return new string[] { "value1", "value2" };
    }

结果如下:

请参考this article

另外,你也可以考虑根据 Authorization 方法对 action 方法进行分组,对于 API-key 相关的 action 方法或控制器,只需添加自定义 API-Key 属性,对于需要 JWT 认证的 action 方法,只需添加[Authorize] 属性。

【讨论】:

  • 谢谢,这正是我想要的 :)
猜你喜欢
  • 2021-03-08
  • 2020-05-14
  • 2021-04-24
  • 2020-07-13
  • 2021-11-06
  • 2020-02-27
  • 2021-06-27
  • 2019-06-05
  • 1970-01-01
相关资源
最近更新 更多