【问题标题】:Customize OWIN/OAuth HTTP status code when rejecting a token request拒绝令牌请求时自定义 OWIN/OAuth HTTP 状态码
【发布时间】:2015-07-25 05:17:43
【问题描述】:

我派生了OAuthAuthorizationServerProvider 以验证客户端和资源所有者。

当我验证资源所有者时,我发现他们的凭据无效,我调用 context.Rejected()HTTP 响应带有 HTTP/400 Bad Request 状态代码,而我预计 HTTP/401 未经授权

如何自定义OAuthAuthorizationServerProvider的响应HTTP状态码?

【问题讨论】:

    标签: c# .net http oauth owin


    【解决方案1】:

    我使用System.Security.Authentication.AuthenticationException 和一个异常中间件采用了稍微不同的方法。

    AuthenticationServerProvider:

    public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
        {
            using (UserManager<IdentityUser> userManager = _userManagerFactory())
            {
                IdentityUser user = await userManager.FindAsync(context.UserName, context.Password);
    
                if (user == null)
                {
                    throw new AuthenticationException("The user name or password is incorrect.");
                }
                ....
    

    中间件:

    public class ExceptionMiddleware : OwinMiddleware
        {
            public ExceptionMiddleware(OwinMiddleware next) : base(next)
            {
            }
    
            public override async Task Invoke(IOwinContext context)
            {
                try
                {
                    await Next.Invoke(context);
                }
                catch (Exception ex)
                {
                    HandleException(ex, context);
                }
            }
    
            private void HandleException(Exception ex, IOwinContext owinContext)
            {
                var errorDetails = new ErrorDetails()
                {
                    Detail = ex.Message,
                    Status = (int)HttpStatusCode.InternalServerError
                };
    
                switch (ex)
                {
                    case AuthenticationException _:
                        errorDetails.Status = (int)HttpStatusCode.Unauthorized;
                        errorDetails.Title = "invalid_grant";
                        break;
                    case [..]
                    case Exception _:
                        errorDetails.Title = "An unexpected error occured";
                        break;
                }
    
                var serializedError = errorDetails.ToString();
                Log.Error($"Returning error response: {serializedError}");
                owinContext.Response.StatusCode = errorDetails.Status;
                owinContext.Response.ContentType = "application/json";
                owinContext.Response.Write(serializedError);
            }
    
            private class ErrorDetails
            {
                public int Status { get; set; }
                public string Title { get; set; }
                public string Detail { get; set; }
    
                public override string ToString()
                {
                    return JsonSerializer.Serialize(this);
                }
            }
    

    应用配置:

    public void Configure(IAppBuilder app)
        ....
            app.Use<ExceptionMiddleware>();
            // Configure auth here
        ....
    
        }
    

    结果:

    【讨论】:

      【解决方案2】:

      这就是我们覆盖 OwinMiddleware 的方式...首先我们在 Owin 之上创建了自己的中间件...我认为我们遇到了与您类似的问题。

      首先需要创建一个常量:

      public class Constants
      {
          public const string OwinChallengeFlag = "X-Challenge";
      }
      

      我们覆盖了 OwinMiddleware

      public class AuthenticationMiddleware : OwinMiddleware
      {
          public AuthenticationMiddleware(OwinMiddleware next) : base(next) { }
      
          public override async Task Invoke(IOwinContext context)
          {
              await Next.Invoke(context);
      
              if (context.Response.StatusCode == 400 && context.Response.Headers.ContainsKey(Constants.OwinChallengeFlag))
              {
                  var headerValues = context.Response.Headers.GetValues(Constants.OwinChallengeFlag);
                  context.Response.StatusCode = Convert.ToInt16(headerValues.FirstOrDefault());
                  context.Response.Headers.Remove(Constants.OwinChallengeFlag);
              }
      
          }
      }
      

      在 startup.Auth 文件中,我们允许覆盖 Invoke Owin 命令

      public void ConfigureAuth(IAppBuilder app)
          ....
              app.Use<AuthenticationMiddleware>(); //Allows override of Invoke OWIN commands
          ....
      
          }
      

      并且在 ApplicationOAuthProvider 中,我们修改了 GrantResourceOwnerCredentials。

      public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
          {
              using (UserManager<IdentityUser> userManager = _userManagerFactory())
              {
                  IdentityUser user = await userManager.FindAsync(context.UserName, context.Password);
      
                  if (user == null)
                  {
                      context.SetError("invalid_grant", "The user name or password is incorrect.");
                      context.Response.Headers.Add(Constants.OwinChallengeFlag, new[] { ((int)HttpStatusCode.Unauthorized).ToString() }); //Little trick to get this to throw 401, refer to AuthenticationMiddleware for more
                      //return;
                  }
                  ....
      

      【讨论】:

      • 我明天试试这个,我会确认你是否对我有用!!提前谢谢你;)
      • 嘿,我正在尝试您的方法,但我发现了问题。我猜STTIAuthenticationMiddlewareAuthenticationMiddleware,我的主要问题是在我的管道期间从不调用自定义中间件。我已经使用app.Use&lt;T&gt;()app.Use(System.Type) 配置了我的中间件。怎么了?
      • 是的,当然。认为身份验证已经在工作。我只是想在拒绝身份验证时将 400 更改为 401。
      • 我设法让中间件工作(这是关于中间件在应用程序中注册的顺序......)。顺便说一句,在设置 401 代码时,响应仍然是 HTTP/400。
      • 当 app.Use() 在 app.UseOAuthAuthorizationServer 之前编写时,答案有效。
      猜你喜欢
      • 2016-08-29
      • 2014-08-10
      • 1970-01-01
      • 2021-02-12
      • 1970-01-01
      • 2016-08-06
      • 2018-08-13
      • 1970-01-01
      • 2011-09-18
      相关资源
      最近更新 更多