拒绝令牌请求时自定义OWIN / OAuth HTTP状态代码

时间:2015-05-13 18:47:20

标签: c# .net http oauth owin

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

当我验证资源所有者时,我发现他们的凭据无效,我调用context.Rejected(),HTTP响应附带 HTTP / 400错误请求状态代码,而我会期待 HTTP / 401未经授权

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

2 个答案:

答案 0 :(得分:14)

这就是我们覆盖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;
            }
            ....

答案 1 :(得分:0)

我采用了略有不同的方法,使用 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
    ....

    }

结果:

enter image description here