今天來做一個webapi的安全管控驗證的案例
我們知道webapi密匙驗證也有不少,比如OAuth2.0.。。。我們今天用JWT這種方式來做一個賬號密碼換取Token的案例
基本流程是 輸入賬號密碼--->后台比對==true -->return Token else 未登錄
所有控制器必須繼承自基礎類,基礎類我們用權限特性控制
老規矩,需要用到的工具
VS2019 NetCore3.1,Postman 調試用
我們看下主要結構如下
記得引用包
我們一個個類來看
1 /// <summary> 2 /// 基礎控制器類 3 /// </summary> 4 [Route("api/[controller]/[action]")] 5 [ApiController] 6 [ActionFilterAttribute] 7 public class BaseController : ControllerBase 8 { 9 /// <summary> 10 /// 獲取Token的方法 11 /// </summary> 12 /// <param name="userId"></param> 13 /// <param name="token1"></param> 14 /// <returns></returns> 15 [NonAction] 16 protected string GetJwtToken(string userId,string token1) 17 { 18 var jwtHandle = new JwtSecurityTokenHandler { }; 19 20 var token = jwtHandle.CreateJwtSecurityToken( 21 "test", 22 "test", 23 new ClaimsIdentity(new Claim[]{ 24 new Claim("name2","tt2"), 25 new Claim("role2","user"), 26 new Claim("token",token1), 27 new Claim("c_uid",userId), 28 }), 29 System.DateTime.Now, 30 //設置過期 31 System.DateTime.Now.AddMilliseconds(3000.00), 32 System.DateTime.Now, 33 new SigningCredentials( 34 new SymmetricSecurityKey(System. 35 Text. 36 Encoding. 37 ASCII.GetBytes("6mSzczZX3KgZ3HOX")), 38 SecurityAlgorithms.HmacSha256) 39 ); 40 41 return jwtHandle.WriteToken(token); 42 } 43 }
這個基礎控制類我們這里就寫一個方法吧,就是生成Token,當然是在匹配用戶名密碼正確之后調用
接下來是這個權限特性 這里都做了注釋,不再一一解釋
/// 權限過濾特性 /// </summary> [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)] public class ActionFilterAttribute : Attribute, IAsyncActionFilter, IAsyncAlwaysRunResultFilter { /// <summary> /// 忽略token的方法 /// </summary> public static readonly string[] IgnoreToken = {"Login"}; /// <summary> /// 校驗過濾器 /// </summary> /// <param name="context"></param> /// <param name="next"></param> /// <returns></returns> public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { //獲取用戶聲明中的Token var UserToken = context.HttpContext.User.FindFirstValue("token"); //執行的動作 var action = context.RouteData.Values["Action"].ToString(); if (IgnoreToken.Count(s => s == action) == 0) { if (UserToken is null) { context.Result = new JsonResult("用戶未登錄!"); return; } //現實中獲取數據庫對比用戶唯一識別token,非加密的那個 if (!UserToken.Equals("123456")) { context.Result = new JsonResult("Token失效!"); return; } } //拋轉下一個中間件 var resultContext = await next(); } /// <summary> /// /// </summary> /// <param name="context"></param> /// <param name="next"></param> /// <returns></returns> public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next) { var resultContext = await next(); }
}
然后我們需要看下StartUp類中我們需要使用這個中間件才可以正常使用
public void ConfigureServices(IServiceCollection services) { //注冊JWT services.AddAuthentication() .AddIdentityServerJwt(); services.Configure<JwtBearerOptions>( IdentityServerJwtConstants.IdentityServerJwtBearerScheme, options => { var onTokenValidated = options.Events.OnTokenValidated; var onMessageReceived = options.Events.OnMessageReceived; options.Events.OnTokenValidated = async context => { await onTokenValidated(context); }; options.Events.OnMessageReceived = async context => { /* https://www.cnblogs.com/liuww/p/12177272.html https://www.cnblogs.com/RainingNight/p/jwtbearer-authentication-in-asp-net-core.html https://www.cnblogs.com/jesse2013/p/integrate-with-lagacy-auth.html https://www.cnblogs.com/nsky/p/10312101.html */ // await onMessageReceived(context); var token = context.Request.Headers["token"]; if (string.IsNullOrEmpty(token)) { token = context.Request.Query["token"]; } context.Token = token.FirstOrDefault(); // return await System.Threading.Tasks.Task.CompletedTask; }; //Token認證注冊 options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters { ValidIssuer = "test", ValidAudience = "test", IssuerSigningKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(System.Text.Encoding.ASCII.GetBytes("6mSzczZX3KgZ3HOX")) }; }); services.AddControllers(); }
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseRouting(); app.UseAuthentication(); //app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); }
上面都寫好之后
我們看下用戶類這里只做兩個東西,一個登錄,一個獲取數據,注意登錄是公開的,獲取用戶信息是私密的
我們運行一下調試看看
打開Postman發現直接調用獲取用戶信息是被拒絕的

好了,我們再嘗試通過用戶名密碼換取Token
我們發現我們成功換取到了token,然后我們再用Token去請求剛才提示拒絕的接口
我們看到已經非常友好的接受了我們的請求。當然這是一個最基本的用戶名密碼換取Token的驗證,如果是前后端分離,我們還要有秘鑰等等驗證,但是小程序里面的話,那么我們可以通過這種驗證實現移動端網頁端的調用。