ASP 核心 API - 自定义未授权主体
ASP Core API - Custom Unauthorized body
我正在使用 dotnet core
v3.1 开发 ASP Core Web API。
我正在使用 JWT 令牌进行身份验证。对于授权,我使用 [Authorize]
属性。
如果用户未登录(在尝试访问标有 [Authorize]
属性的操作时)或用户的令牌未通过身份验证,我如何创建自己的响应。
我遇到了一个使用从默认属性继承的自定义授权属性的解决方案。在这个例子中, HandleUnauthorizedRequest
方法被覆盖了。但是我在 AuthorizeAttribute
class.
中没有看到这样的方法
有没有办法使用 http 正文创建自定义 unauthorized
响应?
由于您使用的是 JWT 承载身份验证,因此覆盖默认挑战逻辑(执行以处理 401 未授权问题)的一种方法是将处理程序挂接到 Startup.ConfigureServices
中的 JwtBearerEvents.OnChallenge
回调:
services.AddAuthentication().AddJwtBearer(options =>
{
// Other configs...
options.Events = new JwtBearerEvents
{
OnChallenge = async context =>
{
// Call this to skip the default logic and avoid using the default response
context.HandleResponse();
// Write to the response in any way you wish
context.Response.StatusCode = 401;
context.Response.Headers.Append("my-custom-header", "custom-value");
await context.Response.WriteAsync("You are not authorized! (or some other custom message)");
}
};
});
这将覆盖 JwtBearerHandler.HandleChallengeAsync
中的默认质询逻辑,您可以找到 here 以供参考。
默认逻辑不写任何内容到response(它只设置状态码和设置一些headers)。因此,要继续使用默认逻辑并在其上添加内容,您可以使用如下内容:
options.Events = new JwtBearerEvents
{
OnChallenge = context =>
{
context.Response.OnStarting(async () =>
{
// Write to the response in any way you wish
await context.Response.WriteAsync("You are not authorized! (or some other custom message)");
});
return Task.CompletedTask;
}
};
对于.net core 5 web api project with jwt authentication 在[=22的Configure方法中使用这个中间件=] 在 Swagger:
中显示 ErrorDto
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "LoginService v1"));
}
app.ConfigureExceptionHandler();
app.UseHttpsRedirection();
app.UseRouting();
// Unauthorized (401) MiddleWare
app.Use(async (context, next) =>
{
await next();
if (context.Response.StatusCode == (int)HttpStatusCode.Unauthorized) // 401
{
context.Response.ContentType = "application/json";
await context.Response.WriteAsync(new ErrorDto()
{
StatusCode = 401,
Message = "Token is not valid"
}.ToString());
}
});
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
ErrorDto :
public class ErrorDto
{
public int StatusCode { get; set; }
public string Message { get; set; }
public override string ToString()
{
return JsonSerializer.Serialize(this);
}
}
这就是我想出的响应方式,与在 ApiController
中返回 Unauthorized()
得到的相同 ProblemDetails
:
.AddJwtBearer(options =>
{
// Other configs...
options.Events = new JwtBearerEvents
{
OnChallenge = async context =>
{
// Call this to skip the default logic and avoid using the default response
context.HandleResponse();
var httpContext = context.HttpContext;
var statusCode = StatusCodes.Status401Unauthorized;
var routeData = httpContext.GetRouteData();
var actionContext = new ActionContext(httpContext, routeData, new ActionDescriptor());
var factory = httpContext.RequestServices.GetRequiredService<ProblemDetailsFactory>();
var problemDetails = factory.CreateProblemDetails(httpContext, statusCode);
var result = new ObjectResult(problemDetails) { StatusCode = statusCode };
await result.ExecuteResultAsync(actionContext);
}
};
});
我正在使用 dotnet core
v3.1 开发 ASP Core Web API。
我正在使用 JWT 令牌进行身份验证。对于授权,我使用 [Authorize]
属性。
如果用户未登录(在尝试访问标有 [Authorize]
属性的操作时)或用户的令牌未通过身份验证,我如何创建自己的响应。
我遇到了一个使用从默认属性继承的自定义授权属性的解决方案。在这个例子中, HandleUnauthorizedRequest
方法被覆盖了。但是我在 AuthorizeAttribute
class.
有没有办法使用 http 正文创建自定义 unauthorized
响应?
由于您使用的是 JWT 承载身份验证,因此覆盖默认挑战逻辑(执行以处理 401 未授权问题)的一种方法是将处理程序挂接到 Startup.ConfigureServices
中的 JwtBearerEvents.OnChallenge
回调:
services.AddAuthentication().AddJwtBearer(options =>
{
// Other configs...
options.Events = new JwtBearerEvents
{
OnChallenge = async context =>
{
// Call this to skip the default logic and avoid using the default response
context.HandleResponse();
// Write to the response in any way you wish
context.Response.StatusCode = 401;
context.Response.Headers.Append("my-custom-header", "custom-value");
await context.Response.WriteAsync("You are not authorized! (or some other custom message)");
}
};
});
这将覆盖 JwtBearerHandler.HandleChallengeAsync
中的默认质询逻辑,您可以找到 here 以供参考。
默认逻辑不写任何内容到response(它只设置状态码和设置一些headers)。因此,要继续使用默认逻辑并在其上添加内容,您可以使用如下内容:
options.Events = new JwtBearerEvents
{
OnChallenge = context =>
{
context.Response.OnStarting(async () =>
{
// Write to the response in any way you wish
await context.Response.WriteAsync("You are not authorized! (or some other custom message)");
});
return Task.CompletedTask;
}
};
对于.net core 5 web api project with jwt authentication 在[=22的Configure方法中使用这个中间件=] 在 Swagger:
中显示 ErrorDtopublic void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "LoginService v1"));
}
app.ConfigureExceptionHandler();
app.UseHttpsRedirection();
app.UseRouting();
// Unauthorized (401) MiddleWare
app.Use(async (context, next) =>
{
await next();
if (context.Response.StatusCode == (int)HttpStatusCode.Unauthorized) // 401
{
context.Response.ContentType = "application/json";
await context.Response.WriteAsync(new ErrorDto()
{
StatusCode = 401,
Message = "Token is not valid"
}.ToString());
}
});
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
ErrorDto :
public class ErrorDto
{
public int StatusCode { get; set; }
public string Message { get; set; }
public override string ToString()
{
return JsonSerializer.Serialize(this);
}
}
这就是我想出的响应方式,与在 ApiController
中返回 Unauthorized()
得到的相同 ProblemDetails
:
.AddJwtBearer(options =>
{
// Other configs...
options.Events = new JwtBearerEvents
{
OnChallenge = async context =>
{
// Call this to skip the default logic and avoid using the default response
context.HandleResponse();
var httpContext = context.HttpContext;
var statusCode = StatusCodes.Status401Unauthorized;
var routeData = httpContext.GetRouteData();
var actionContext = new ActionContext(httpContext, routeData, new ActionDescriptor());
var factory = httpContext.RequestServices.GetRequiredService<ProblemDetailsFactory>();
var problemDetails = factory.CreateProblemDetails(httpContext, statusCode);
var result = new ObjectResult(problemDetails) { StatusCode = statusCode };
await result.ExecuteResultAsync(actionContext);
}
};
});