c# - 在 .NET Core 中使用 JWT token 或 API key 的授权机制

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

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

可以找到示例代码here

最佳答案

I was trying to create an API-key attribute in a way shown here and decorate all controllers with it but, this was only working when no [Authorize] attribute was set. When I set [Authorize] attribute and set a breakpoint in my API-key attribute it will never be reached and I'm getting 401 Unauthorized as a response.

问题涉及当自定义 API-Key 属性与 [Authorize] 属性一起使用时, Controller 或操作方法将同时配置 JWT 身份验证和 API-Key 验证,在请求中 header ,它应该包含 JWT token 和 API-Key。如果缺少任何一个,它将显示 401 Unauthorized 错误。

Is there any chance to have both authorization methods working in parallel? If so, please guide me on how to achieve that.

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

例如:使用以下代码创建一个 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 Controller 中使用上面的 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" };
    }

结果是这样的:

enter image description here

引用this article .

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

关于c# - 在 .NET Core 中使用 JWT token 或 API key 的授权机制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66645141/

相关文章:

c# - 为什么在 C# 中没有引用计数 + 垃圾收集?

c# - 用于客户端/服务器通信的命名管道或 TCP

c# - MVVM:我是否使用事件或方法调用在 ViewModel 和 Model 之间进行通信

asp.net-core - 身份服务器 4 用户管理 API

C# 内存分配、GC、死对象不匹配的内存诊断

Django-allauth、JWT、Oauth

c# - 传递 web api 参数时出现 404

asp.net-core - .NET Core 静态代码分析工具

Angular 文本编辑器上传图像请求未发送授权 header (JWT token )

json - JWT(JSON Web token )是否有人嗅探 token ,是否可以发送相同的帖子?