闽公网安备 35020302035485号
3.校验通过的话,接口里需要能访问到对应的 Client 对象
var client = HttpContext.Items["client"] as Client;
public enum ClientIdSource {
Query,
Body,
Route,
Header
}
ValidateClientAttribute 实现public class ValidateClientAttribute( ClientIdSource source = ClientIdSource.Query) : ActionFilterAttribute {
/// <summary>
/// 堆代码 duidaima.com
/// 客户端ID的参数名称,注意是 DTO 里的属性名称,不是请求体JSON的字段名
/// </summary>
public string ParameterName { get; set; } = "client_id";
/// <summary>
/// 设置验证成功之后,存储在 `HttpContext.Items` 对象中的 `Client` 对象的 key
/// </summary>
public string ClientItemKey { get; set; } = "client";
public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) {
var clientId = "";
switch (source) {
case ClientIdSource.Query:
clientId = context.HttpContext.Request.Query[ParameterName];
break;
case ClientIdSource.Body:
// 使用反射从请求体中读取 client_id
// 这里读取到的 body 是 Controller 下 Action 方法的第一个参数,通常是请求体中的 JSON 数据模型绑定转换为对应 DTO 实例
var body = context.ActionArguments.Values.FirstOrDefault();
if (body != null) {
var clientProp = body.GetType().GetProperty(ParameterName);
if (clientProp != null) {
clientId = clientProp.GetValue(body) as string;
}
}
break;
case ClientIdSource.Route:
clientId = context.RouteData.Values[ParameterName] as string;
break;
case ClientIdSource.Header:
clientId = context.HttpContext.Request.Headers[ParameterName];
break;
}
if (string.IsNullOrWhiteSpace(clientId)) {
throw new ArgumentNullException(ParameterName);
}
var clientRepo = context.HttpContext.RequestServices.GetRequiredService<IBaseRepository<Client>>();
var client = await clientRepo.Select.Where(a => a.ClientId == clientId).FirstAsync();
if (client != null) {
context.HttpContext.Items["client"] = client;
await next();
}
else {
context.Result = new NotFoundObjectResult(
new ApiResponse { Message = $"client with id {clientId} not found" });
}
}
}
有几点需要注意的,下面介绍一下:其他几个参数位置还好,获取都比较容易,如果是 POST 或者 PUT 方法,一般都是把数据以 JSON 的形式放在 Request Body 里,这个时候,我们可以去读取这个 Body 的值,但读取完之后得自己解析 JSON,还得把 Stream 写回去,有点麻烦。而且如果 Body 是 XML 形式,还要用其他的解析方式。这里我使用了反射的方式,让 AspNetCore 框架去处理这个 Request Body ,然后我直接用反射,根据参数名去读取 Client ID。
使用
这是几个使用例子public class PwdLoginDto : LoginDto {
[Required]
[JsonPropertyName("username")]
public string Username { get; set; }
[Required]
[JsonPropertyName("password")]
public string Password { get; set; }
}
在接口中使用[HttpPost("login/password")]
[ValidateClient(ClientIdSource.Body, ParameterName = "ClientId")]
public async Task<IActionResult> LoginByPassword(PwdLoginDto dto) {
}
参数在 Query Params 里[HttpGet("authorize/url")]
[ValidateClient(ClientIdSource.Query, ParameterName = "client_id")]
public ApiResponse<string> GetAuthorizeUrl([FromQuery] AuthorizeInput input) {
return new ApiResponse<string>(GenerateAuthorizeUrl(input));
}