.Net WebApi 中的Token参数校验
一、引言
在当今数字化浪潮席卷的时代,Web 应用如雨后春笋般蓬勃发展,深入到我们生活的方方面面。无论是在线购物、社交互动,还是金融交易,我们都与 Web 应用紧密相连。而在这繁荣的背后,安全性和可靠性犹如大厦的基石,成为保障 Web 应用稳健运行、用户信息安全的关键要素。
当我们聚焦于 WebAPI 时,一个不容忽视的核心需求便是对请求进行严格的身份验证。在众多身份验证方式中,通过 Token 来验证用户身份的方法脱颖而出,备受青睐。Token 就像是一把独特的 “钥匙”,只有持有正确 “钥匙” 的用户,才能顺利打开对应资源的 “大门”。同时,确保传入的参数准确无误、安全可靠,也是 WebAPI 开发中不可或缺的重要环节。参数校验能够有效防止恶意的数据注入,如同坚固的盾牌,抵御外界的恶意攻击,为系统的稳定性和安全性保驾护航。
在本文中,我将带领大家深入探索在.Net WebApi 中实现 Token 和参数校验的多种实用方法,并附上详细的代码示例。这些方法和示例,就像是为开发者们精心准备的 “工具包”,能够帮助大家更好地理解并在实际项目中高效实施这些关键技术,为打造安全可靠的 Web 应用筑牢坚实的防线。
二、为什么需要校验 Token / 参数
在 WebAPI 的世界里,每一次请求都像是一位不速之客,怀揣着各种可能的目的。恶意攻击者可能会伪装成合法用户,试图窃取敏感信息、篡改数据,甚至破坏系统的正常运行。这绝非危言耸听,而是实实在在存在的风险。而校验 Token,就像是为 WebAPI 配备了一位火眼金睛的 “门卫”。通过验证 Token,我们能够确认请求的来源是否可信,判断请求者是否真的是其所声称的用户。只有当 Token 验证通过,才意味着请求者持有合法的 “入场券”,被允许访问受保护的资源。
而校验参数,则是为 WebAPI 筑牢了一道坚固的 “防护墙”,有效抵御恶意数据注入的攻击。在现实中,恶意攻击者可能会精心构造一些特殊的参数值,试图利用系统的漏洞进行 SQL 注入、XSS 攻击等。这些攻击手段一旦得逞,后果不堪设想,可能导致数据库中的敏感信息泄露,如用户的账号密码、个人隐私数据等;也可能导致网页被篡改,展示给用户虚假的信息;甚至可能使整个系统陷入瘫痪,无法正常提供服务。通过对参数进行严格校验,我们可以确保传入的数据符合预期的格式、范围和业务规则,从而有效地防止这些恶意攻击的发生。
三、如何校验 Token
3.1 使用 OAuth2 和 JWT
OAuth2 是一种广泛应用的授权协议,它就像是一个精心设计的 “权限分配系统”,允许用户授权第三方应用访问特定的资源,而无需将自己的用户名和密码直接提供给第三方。打个比方,OAuth2 就像是你去图书馆借书,不需要把自己家的钥匙(用户名和密码)交给图书管理员,而是通过图书馆颁发的一张临时借阅证(Token)来借阅书籍。
JWT(JSON Web Tokens)则是一种紧凑、安全的信息传输方式,它将信息以 JSON 对象的形式在各方之间传递。JWT 包含了三部分:头部(Header)、负载(Payload)和签名(Signature)。头部通常包含了签名算法等信息,就像是信封上的寄件人信息;负载则存放着实际的用户信息、过期时间等重要内容,如同信封里的信件内容;签名则用于验证消息的完整性和真实性,防止信息被篡改,就像信封上的封印,确保信件在传递过程中没有被拆开过。
在 WebApi 中,我们可以通过以下步骤来实现基于 JWT 的 Token 校验 :
// 添加必要的NuGet包
// Install-Package Microsoft.AspNet.WebApi.Owin.Security.Jwt
// Install-Package Microsoft.Owin.Security.Jwt
using Owin;
using Microsoft.Owin;
using Microsoft.Owin.Security.OAuth;
using System.Web.Http;
public static class WebApiConfig {
public static void Register(HttpConfiguration config) {
var oAuthServerOptions = new OAuthAuthorizationServerOptions {
AllowInsecureClient = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new SimpleProvider()
};
app.UseOAuthBearerTokens(oAuthServerOptions);
// 其他WebApi配置...
}
public class SimpleProvider : OAuthAuthorizationServerProvider {
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context) {
context.Validated();
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) {
context.OwinContext.Response.Body = new StringContent(
$"access_token={context.CreateAccessToken().ToString()}&token_type=bearer");
context.RequestCompleted();
}
}
}
上述代码中,我们使用了 Owin 和 OAuthAuthorizationServerOptions 来配置 OAuth 服务。SimpleProvider 类继承自 OAuthAuthorizationServerProvider,并重写了 ValidateClientAuthentication 和 GrantResourceOwnerCredentials 方法。ValidateClientAuthentication 方法用于验证客户端身份,在这个示例中,我们简单地将其设置为总是验证通过。GrantResourceOwnerCredentials 方法则用于发放访问令牌,当用户提供正确的用户名和密码后,该方法会生成一个访问令牌,并将其返回给客户端。
3.2 自定义过滤器
除了使用 OAuth 这种相对成熟的框架外,我们还可以通过创建自定义的过滤器来实现 Token 校验。这种方式就像是为 WebApi 打造了一个专属的 “安检门”,可以根据我们的特定需求进行灵活调整。
自定义过滤器的实现方式如下:
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Http.Filters;
public class TokenValidationFilter : AuthorizationFilterAttribute {
public override void OnAuthorization(AuthorizationContext filterContext) {
var token = filterContext.RequestContext.HttpContext.Request.Headers["Authorization"];
if (string.IsNullOrEmpty(token)) {
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.Unauthorized));
}
// 进行Token有效性检查
if (!IsValidToken(token)) {
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.Forbidden));
}
}
private bool IsValidToken(string token) {
// 这里应实现Token校验逻辑
return true; // 示例中假定Token总是有效的
}
}
public class ValuesController : ApiController {
[HttpGet]
[TokenValidationFilter]
public IHttpActionResult Get() {
return Ok(new { message = "Access granted." });
}
}
在这段代码中,我们定义了一个名为 TokenValidationFilter 的自定义过滤器,它继承自 AuthorizationFilterAttribute。在 OnAuthorization 方法中,我们检查请求头中的 Authorization 字段。如果该字段为空,说明请求中没有携带 Token,我们就抛出一个 HttpResponseException 异常,并返回 HTTP 401 Unauthorized 状态码,表示未经授权。如果 Token 存在,我们调用 IsValidToken 方法来检查 Token 的有效性。在实际应用中,IsValidToken 方法应包含具体的 Token 校验逻辑,例如验证 Token 的签名、过期时间等。在这个示例中,我们暂时将其设置为总是返回 true,表示 Token 总是有效的。
在 ValuesController 控制器中,我们在 Get 方法上应用了 TokenValidationFilter 过滤器。这意味着当客户端发送一个 GET 请求到这个控制器的 Get 方法时,系统会首先执行 TokenValidationFilter 过滤器中的 OnAuthorization 方法,对请求进行 Token 校验。只有当 Token 校验通过后,才会执行 Get 方法,并返回 “Access granted.” 的响应。
3.3 使用中间件校验 Token
中间件是一种能够在请求处理管道中发挥重要作用的组件,它就像是 WebApi 中的一个个 “关卡”,可以在请求到达控制器之前,对请求进行拦截和处理。通过创建自定义中间件,我们可以在每个请求到达控制器之前,对 Token 进行校验。
示例代码如下:
public class TokenMiddleware {
private readonly RequestDelegate _next;
public TokenMiddleware(RequestDelegate next) {
_next = next;
}
public async Task InvokeAsync(HttpContext context) {
if (!context.Request.Headers.TryGetValue("Authorization", out StringValues token)) {
context.Response.StatusCode = 401;
await context.Response.WriteAsync("Token is missing");
return;
}
// 这里可以添加更多的token校验逻辑,比如使用JWT库验证token
if (!IsValidToken(token)) {
context.Response.StatusCode = 403;
await context.Response.WriteAsync("Invalid Token");
return;
}
// 调用管道中的下一个中间件
await _next(context);
}
private bool IsValidToken(string token) {
// 实际的token验证逻辑
return true;
}
}
在上述代码中,TokenMiddleware 类的构造函数接收一个 RequestDelegate 类型的参数_next,它代表了请求处理管道中的下一个中间件。在 InvokeAsync 方法中,我们首先尝试从请求头中获取 Authorization 字段的值,即 Token。如果获取失败,说明请求中没有携带 Token,我们设置响应状态码为 401(Unauthorized),并返回 “Token is missing” 的错误信息。如果获取到了 Token,我们调用 IsValidToken 方法来验证 Token 的有效性。如果 Token 无效,我们设置响应状态码为 403(Forbidden),并返回 “Invalid Token” 的错误信息。只有当 Token 有效时,我们才调用_next (context),将请求传递给下一个中间件进行处理。
要在项目中使用这个中间件,我们需要在 Startup.cs 文件中进行配置:
public class Startup {
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
app.UseMiddleware<TokenMiddleware>();
// 其他中间件配置...
}
}
在 Configure 方法中,我们使用 app.UseMiddleware() 来注册 TokenMiddleware 中间件。这样,当请求进入应用程序时,就会首先经过 TokenMiddleware 中间件的处理,对 Token 进行校验。
3.4 使用 ActionFilter 校验 Token
ActionFilter 是一种特殊的过滤器,它可以在请求到达控制器方法之前和之后执行特定的逻辑。通过创建自定义的 ActionFilter,我们可以在每个需要校验 Token 的 Action 上,轻松地应用校验逻辑。
示例代码如下:
public class TokenActionFilter : IActionFilter {
public void OnActionExecuting(ActionExecutingContext context) {
if (!context.HttpContext.Request.Headers.TryGetValue("Authorization", out StringValues token)) {
context.Result = new StatusCodeResult(401);
return;
}
// 这里可以添加更多的token校验逻辑
if (!IsValidToken(token)) {
context.Result = new StatusCodeResult(403);
return;
}
}
public void OnActionExecuted(ActionExecutedContext context) {
// 可以在这里处理Action执行后的逻辑
}
private bool IsValidToken(string token) {
// 实际的token验证逻辑
return true;
}
}
在 TokenActionFilter 类中,我们实现了 IActionFilter 接口。OnActionExecuting 方法会在 Action 执行之前被调用,在这个方法中,我们首先尝试从请求头中获取 Token。如果获取失败,我们设置 context.Result 为一个表示 401 状态码的 StatusCodeResult 对象,即返回未经授权的响应。如果获取到了 Token,我们调用 IsValidToken 方法来验证 Token 的有效性。如果 Token 无效,我们设置 context.Result 为一个表示 403 状态码的 StatusCodeResult 对象,即返回禁止访问的响应。只有当 Token 有效时,才会继续执行后续的 Action。
OnActionExecuted 方法会在 Action 执行之后被调用,在这个方法中,我们可以处理一些 Action 执行后的逻辑,比如记录日志、清理资源等。在这个示例中,我们暂时没有在这个方法中添加具体的逻辑。
要在控制器或 Action 上应用这个 ActionFilter,我们可以使用以下方式:
[ApiController]
[Route("api/[controller]")]
[ServiceFilter(typeof(TokenActionFilter))]
public class ValuesController : ControllerBase {
[HttpGet]
public IActionResult Get() {
return Ok(new string[] { "value1", "value2" });
}
}
在 ValuesController 控制器类上,我们使用了 [ServiceFilter (typeof (TokenActionFilter))] 特性,这表示对这个控制器中的所有 Action 都应用 TokenActionFilter 过滤器。当客户端发送一个请求到 ValuesController 控制器的任何 Action 时,都会首先执行 TokenActionFilter 过滤器中的 OnActionExecuting 方法,对 Token 进行校验。只有当 Token 校验通过后,才会执行相应的 Action。如果我们只想对某个特定的 Action 应用过滤器,可以将 [ServiceFilter (typeof (TokenActionFilter))] 特性直接应用到该 Action 上。
四、如何校验参数
4.1 使用 DataAnnotations
在参数校验的领域中,.NET Framework 为我们提供了一位得力助手 ——DataAnnotations。它就像是一套精心设计的 “检查工具”,能够帮助我们高效地校验模型。
下面通过一个具体的示例来展示它的强大功能。假设我们有一个处理用户注册信息的 API,需要对用户输入的姓名和邮箱进行校验,确保数据的准确性和完整性。我们可以定义如下的模型类:
public class UserRequest {
[Required(ErrorMessage = "The Name field is required.")]
[StringLength(100, ErrorMessage = "The Name must be at least 6 characters long.", MinimumLength = 6)]
public string Name { get; set; }
[RegularExpression(@"^[\w\.-]+@[\w\.-]+\.\w+$", ErrorMessage = "Invalid email format.")]
public string Email { get; set; }
}
在这个模型类中,我们使用了 DataAnnotations 提供的多个特性来进行校验。[Required]特性表示该字段是必填项,如果用户在请求中没有提供该字段的值,系统将会返回一个错误提示,告知用户该字段是必需的。[StringLength]特性则用于限制字符串的长度,在这里,我们要求姓名的长度至少为 6 个字符,最长不超过 100 个字符。如果用户输入的姓名长度不符合这个范围,系统也会返回相应的错误信息。[RegularExpression]特性用于验证字段是否符合指定的正则表达式,在这个例子中,我们使用正则表达式来验证邮箱地址的格式是否正确。只有当用户输入的邮箱地址符合这个正则表达式的模式时,才会被认为是有效的邮箱地址。
接下来,我们在控制器中使用这个模型类来处理用户的注册请求:
public class AccountController : ApiController {
[HttpPost]
public HttpResponseMessage Post([FromBody]UserRequest user) {
if (!ModelState.IsValid) {
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
}
// 处理逻辑...
return Request.CreateResponse(HttpStatusCode.Created);
}
}
在控制器的Post方法中,我们通过ModelState.IsValid来检查模型的状态是否有效。如果模型中的任何一个字段没有通过我们在模型类中定义的校验规则,ModelState.IsValid将会返回false。此时,我们使用Request.CreateErrorResponse方法返回一个 HTTP 400 Bad Request 响应,并将ModelState传递给这个方法,这样客户端就可以获取到详细的错误信息,了解哪些字段没有通过校验以及具体的错误原因。如果所有字段都通过了校验,ModelState.IsValid将返回true,我们就可以继续处理用户的注册请求,例如将用户信息保存到数据库中,并返回一个 HTTP 201 Created 响应,表示资源已成功创建。
4.2 自定义校验逻辑
虽然 DataAnnotations 提供了很多实用的校验特性,但在实际项目中,我们可能会遇到一些更加复杂的校验需求,这些需求无法通过现有的特性直接满足。这时候,我们就需要编写自定义的校验逻辑,来确保参数的有效性。
例如,我们需要对用户输入的密码进行强度校验,要求密码必须包含至少一个大写字母、一个小写字母、一个数字和一个特殊字符,并且长度在 8 到 16 位之间。我们可以通过以下方式来实现:
public class AccountController : ApiController {
[HttpPost]
public HttpResponseMessage Post([FromBody]UserRequest user) {
if (!IsValidPassword(user.Password)) {
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, "Invalid password. Password must contain at least one uppercase letter, one lowercase letter, one digit, one special character, and be between 8 and 16 characters long.");
}
// 处理逻辑...
return Request.CreateResponse(HttpStatusCode.Created);
}
private bool IsValidPassword(string password) {
if (string.IsNullOrEmpty(password) || password.Length < 8 || password.Length > 16) {
return false;
}
bool hasUpper = false;
bool hasLower = false;
bool hasDigit = false;
bool hasSpecialChar = false;
foreach (char c in password) {
if (char.IsUpper(c)) {
hasUpper = true;
} else if (char.IsLower(c)) {
hasLower = true;
} else if (char.IsDigit(c)) {
hasDigit = true;
} else if (IsSpecialChar(c)) {
hasSpecialChar = true;
}
}
return hasUpper && hasLower && hasDigit && hasSpecialChar;
}
private bool IsSpecialChar(char c) {
string specialChars = @"!@#$%^&*()_+-=[]{}|;':""<>,./?";
return specialChars.Contains(c);
}
}
在上述代码中,我们在AccountController的Post方法中调用了IsValidPassword方法来校验用户输入的密码。IsValidPassword方法首先检查密码是否为空,以及长度是否在 8 到 16 位之间。如果不满足这些条件,直接返回false。然后,通过遍历密码中的每个字符,检查是否包含大写字母、小写字母、数字和特殊字符。这里定义了一个IsSpecialChar方法来判断一个字符是否为特殊字符。只有当密码同时满足所有这些条件时,IsValidPassword方法才会返回true,表示密码强度符合要求。如果密码不符合要求,Post方法会返回一个 HTTP 400 Bad Request 响应,并附带详细的错误信息,告知用户密码的具体要求。
4.3 使用路由模板校验参数
在 WebAPI 开发中,使用路由模板对请求参数进行校验是一种简洁而高效的方式。它就像是为请求参数设置了一道 “关卡”,只有符合特定规则的参数才能顺利通过。
路由模板的格式非常直观,为{参数名:规则}。其中,规则部分可以是各种内置的校验规则,也可以是我们自定义的规则。
先来看一些内置规则的示例。假设我们有一个获取用户信息的 API,需要根据用户 ID 来获取对应的用户数据。我们可以通过路由模板来限制用户 ID 必须是一个正整数,并且在一定范围内。示例代码如下:
[HttpGet("api/users/{id:int:min(1)}")]
public IHttpActionResult GetUser(int id) {
// 根据id获取用户信息的逻辑
return Ok(user);
}
在这个例子中,{id:int:min(1)}表示id参数必须是一个整数类型,并且最小值为 1。如果客户端发送的请求中id参数不符合这个规则,例如传入了一个非整数或者小于 1 的值,系统将会自动返回一个 HTTP 400 Bad Request 响应,提示参数错误。
再比如,我们有一个处理订单的 API,需要根据订单编号来查询订单信息。订单编号是一个字符串类型,并且要求长度必须为 10 位。代码如下:
[HttpGet("api/orders/{orderNumber:string:length(10)}")]
public IHttpActionResult GetOrder(string orderNumber) {
// 根据orderNumber获取订单信息的逻辑
return Ok(order);
}
这里{orderNumber:string:length(10)}表示orderNumber参数必须是一个字符串类型,并且长度恰好为 10 位。如果参数长度不符合要求,同样会返回 HTTP 400 Bad Request 响应。
除了这些基本的规则,路由模板还支持正则表达式校验。例如,我们有一个 API 用于处理用户登录,需要验证用户名是否符合特定的格式,用户名只能包含字母、数字和下划线,并且长度在 3 到 20 位之间。可以这样实现:
[HttpPost("api/login/{username:string:regex(^[a-zA-Z0-9_]{3,20}$)}")]
public IHttpActionResult Login(string username, string password) {
// 登录验证的逻辑
return Ok(result);
}
在这个例子中,{username:string:regex(1{3,20}KaTeX parse error: Expected 'EOF', got '}' at position 2: )}̲使用正则表达式^[a-zA-Z…来校验username参数。这个正则表达式表示用户名必须以字母、数字或下划线开头和结尾,并且长度在 3 到 20 位之间。如果用户名不符合这个正则表达式的模式,请求将被拒绝,并返回相应的错误响应。
当内置规则无法满足我们的需求时,我们还可以创建自定义的路由约束。假设我们有一个 API 需要根据用户的年龄来获取特定的内容,并且要求年龄必须是一个有效的成年人年龄(大于等于 18 岁)。我们可以通过以下步骤来实现自定义的路由约束。
首先,创建一个实现IRouteConstraint接口的类,在这个类中编写我们的自定义校验逻辑:
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using System;
public class AdultAgeConstraint : IRouteConstraint {
public bool Match(HttpContext httpContext, IRouter route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection) {
if (routeDirection == RouteDirection.IncomingRequest) {
if (values.TryGetValue(routeKey, out object value) && value!= null) {
if (int.TryParse(value.ToString(), out int age) && age >= 18) {
return true;
}
}
}
return false;
}
}
在这个类中,Match方法是实现自定义校验逻辑的核心部分。它首先检查请求的方向是否为传入请求(RouteDirection.IncomingRequest),然后尝试从RouteValueDictionary中获取指定参数的值。如果获取到的值可以转换为整数,并且这个整数大于等于 18,就返回true,表示参数符合要求;否则返回false。
接下来,我们需要在Startup.cs文件中注册这个自定义的路由约束:
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
public class Startup {
public void ConfigureServices(IServiceCollection services) {
services.AddRouting(options => {
options.ConstraintMap.Add("adultAge", typeof(AdultAgeConstraint));
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
if (env.IsDevelopment()) {
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(endpoints => {
endpoints.MapGet("api/ageRestricted/{age:adultAge}", async context => {
// 根据年龄获取特定内容的逻辑
await context.Response.WriteAsync("Content for adults only.");
});
});
}
}
在ConfigureServices方法中,我们使用options.ConstraintMap.Add(“adultAge”, typeof(AdultAgeConstraint))将自定义的路由约束AdultAgeConstraint注册到路由系统中,并给它命名为adultAge。在Configure方法中,我们定义了一个路由,其中{age:adultAge}表示age参数将使用我们刚刚注册的自定义路由约束进行校验。只有当age参数满足我们定义的成年人年龄条件时,请求才能被正确处理。
五、总结
在这篇文章中,我们全面且深入地探讨了在.Net WebApi 中实现 Token 和参数校验的多种行之有效的方法。从 Token 校验的角度来看,OAuth2 和 JWT 的组合为我们提供了一种标准且广泛应用的解决方案,它借助成熟的授权协议和安全的信息传输格式,确保了用户身份验证的可靠性和安全性。自定义过滤器则赋予了我们更大的灵活性,使我们能够根据项目的独特需求,量身定制校验逻辑。而中间件和 ActionFilter 的使用,从不同层面切入请求处理流程,为 Token 校验提供了多样化的实现途径。
在参数校验方面,DataAnnotations 以其简洁明了的特性,为我们提供了一种便捷的方式来验证模型参数。通过在模型类上添加各种特性,如[Required]、[StringLength]、[RegularExpression]等,我们能够轻松地对参数进行必填性、长度、格式等方面的校验。自定义校验逻辑则适用于那些更为复杂的校验场景,当现有的校验特性无法满足需求时,我们可以编写自定义的校验方法,实现对参数的深度验证。使用路由模板校验参数,无论是内置规则还是自定义约束,都为我们在路由层面提供了一种高效的参数校验手段,使请求参数在进入控制器之前就得到严格的筛选。
这些校验方法就像是为 WebAPI 打造的一套坚固的 “安全铠甲”,每一种方法都在保障 WebAPI 的安全性和可靠性方面发挥着不可或缺的作用。它们能够有效地防止未经授权的访问,抵御恶意攻击,确保系统的稳定运行,保护用户的信息安全。
在实际项目中,我们应根据项目的具体需求、架构特点以及安全要求,灵活选择合适的校验方法。有时候,单一的校验方法可能就足以满足需求;而在一些对安全性要求极高的场景下,我们可能需要综合运用多种校验方法,形成多层次的安全防护体系。
同时,我们也要清醒地认识到,安全领域是一个不断发展、持续变化的领域。随着技术的不断进步,新的攻击手段层出不穷,安全威胁也日益复杂多样。因此,我们需要保持敏锐的洞察力,持续关注最新的安全动态,不断学习和掌握新的安全实践和技术。只有这样,我们才能在不断变化的安全环境中,始终为我们的 WebAPI 筑牢安全防线,确保其能够稳定、可靠地为用户提供服务。
a-zA-Z0-9_ ↩︎
原文地址:https://blog.csdn.net/weixin_44064908/article/details/145189355
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!