Asp.Net Core基于JWT认证的数据接口网关实例代码
前言
近日,应一位朋友的邀请写了个Asp.Net Core基于JWT认证的数据接口网关Demo。朋友自己开了个公司,接到的一个升级项目,客户要求用Aps.Net Core做数据网关服务且基于JWT认证实现对前后端分离的数据服务支持,于是想到我一直做.Net开发,问我是否对.Net Core有所了解?能不能做个简单Demo出来看看?我说,分道扬镳之后我不是调用别人的接口就是提供接口给别人调用,于是便有了以下示例代码。
示例要求能演示获取Token及如何使用该Token访问数据资源,在Demo中实现了JWT的颁发及验证以及重写一个ActionAuthorizeAttribute实现对具体数据接口的调用权限控制,先看一下项目截图:
[项目截图]
项目文件介绍
解决方案下只有一个项目,项目名称就叫Jwt.Gateway,包含主要文件有:
- Controllers目录下的ApiActionFilterAttribute.cs文件,继承Microsoft.AspNetCore.Mvc.Filters.ActionFilterAttribute,用于校验接口调用者对具体接口的访问权限。
- Controllers目录下的ApiBase.cs文件,继承Microsoft.AspNetCore.Mvc.Controller,具有Microsoft.AspNetCore.Authorization.Authorize特性引用,用于让所有数据接口用途的控制器继承,定义有CurrentAppKey属性(来访应用程序的身份标识)并在OnActionExecuting事件中统一分析Claims并赋值。
- Controllers目录下的TokenController.cs控制器文件,用于对调用方应用程序获取及注销Token。
- Controllers目录下的UsersController.cs控制器文件,继承ApiBase.cs,作为数据调用示例。
- MiddleWares目录下的ApiCustomException.cs文件,是一个数据接口的统一异常处理中间件。
- Models目录下的ApiResponse.cs文件,用于做数据接口的统一数据及错误信息输出实体模型。
- Models目录下的User.cs文件,示例数据实体模型。
- Program.cs及Startup.cs文件就不介绍了,随便建个空项目都有。
项目文件代码
ApiActionFilterAttribute.cs
Controllers目录下的ApiActionFilterAttribute.cs文件,继承Microsoft.AspNetCore.Mvc.Filters.ActionFilterAttribute,用于校验接口调用者对具体接口的访问权限。
设想每一个到访的请求都是一个应用程序,每一个应用程序都分配有基本的Key和Password,每一个应用程序具有不同的接口访问权限,所以在具体的数据接口上应该声明该接口所要求的权限值,比如修改用户信息的接口应该在接口方法上声明需要具有“修改用户”的权限,用例: [ApiActionFilter("用户修改")]
。
大部分情况下一个接口(方法)对应一个操作,这样基本上就能应付了,但是不排除有时候可能需要多个权限组合进行验证,所以该文件中有一个对多个权限值进行校验的“与”和“和”枚举,用例: [ApiActionFilter(new string[] { "用户修改", "用户录入", "用户删除" },ApiActionFilterAttributeOption.AND)]
,这样好像就差不多了。
由于在一个接口调用之后可能需要将该接口所声明需要的权限值记入日志等需求,因此权限值集合将被写入到HttpContext.Items["Permissions"]中以方便可能的后续操作访问,看代码:
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc.Filters; namespace Jwt.Gateway.Controllers { public enum ApiActionFilterAttributeOption { OR,AND } public class ApiActionFilterAttribute : Microsoft.AspNetCore.Mvc.Filters.ActionFilterAttribute { List<string> Permissions = new List<string>(); ApiActionFilterAttributeOption Option = ApiActionFilterAttributeOption.AND; public ApiActionFilterAttribute(string permission) { Permissions.Add(permission); } public ApiActionFilterAttribute(string[] permissions, ApiActionFilterAttributeOption option) { foreach(var permission in permissions) { if (Permissions.Contains(permission)) { continue; } Permissions.Add(permission); } Option = option; } public override void OnActionExecuting(ActionExecutingContext context) { var key = GetAppKey(context); List<string> keyPermissions = GetAppKeyPermissions(key); var isAnd = Option == ApiActionFilterAttributeOption.AND; var permissionsCount = Permissions.Count; var keyPermissionsCount = keyPermissions.Count; for (var i = 0; i < permissionsCount; i++) { bool flag = false; for (var j = 0; j < keyPermissions.Count; j++) { if (flag = string.Equals(Permissions[i], keyPermissions[j], StringComparison.OrdinalIgnoreCase)) { break; } } if (flag) { continue; } if (isAnd) { throw new Exception("应用“" + key + "”缺少“" + Permissions[i] + "”的权限"); } } context.HttpContext.Items.Add("Permissions", Permissions); base.OnActionExecuting(context); } private string GetAppKey(ActionExecutingContext context) { var claims = context.HttpContext.User.Claims; if (claims == null) { throw new Exception("未能获取到应用标识"); } var claimKey = claims.ToList().Find(o => string.Equals(o.Type, "AppKey", StringComparison.OrdinalIgnoreCase)); if (claimKey == null) { throw new Exception("未能获取到应用标识"); } return claimKey.Value; } private List<string> GetAppKeyPermissions(string appKey) { List<string> li = new List<string> { "用户明细","用户列表","用户录入","用户修改","用户删除" }; return li; } } } ApiActionAuthorizeAttribute.cs
ApiBase.cs
Controllers目录下的ApiBase.cs文件,继承Microsoft.AspNetCore.Mvc.Controller,具有Microsoft.AspNetCore.Authorization.Authorize特性引用,用于让所有数据接口用途的控制器继承,定义有CurrentAppKey属性(来访应用程序的身份标识)并在OnActionExecuting事件中统一分析Claims并赋值。
通过验证之后,Aps.Net Core会在HttpContext.User.Claims中将将来访者的身份信息记录下来,我们可以通过该集合得到来访者的身份信息。
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; namespace Jwt.Gateway.Controllers { [Microsoft.AspNetCore.Authorization.Authorize] public class ApiBase : Microsoft.AspNetCore.Mvc.Controller { private string _CurrentAppKey = ""; public string CurrentAppKey { get { return _CurrentAppKey; } } public override void OnActionExecuting(ActionExecutingContext context) { var claims = context.HttpContext.User.Claims.ToList(); var claim = claims.Find(o => o.Type == "appKey"); if (claim == null) { throw new Exception("未通过认证"); } var appKey = claim.Value; if (string.IsNullOrEmpty(appKey)) { throw new Exception("appKey不合法"); } _CurrentAppKey = appKey; base.OnActionExecuting(context); } } } ApiBase.cs
TokenController.cs
Controllers目录下的TokenController.cs控制器文件,用于对调用方应用程序获取及注销Token。
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; namespace Jwt.Gateway.Controllers { [Route("api/[controller]/[action]")] public class TokenController : Controller { private readonly Microsoft.Extensions.Configuration.IConfiguration _configuration; public TokenController(Microsoft.Extensions.Configuration.IConfiguration configuration) { _configuration = configuration; } // /api/token/get public IActionResult Get(string appKey, string appPassword) { try { if (string.IsNullOrEmpty(appKey)) { throw new Exception("缺少appKey"); } if (string.IsNullOrEmpty(appKey)) { throw new Exception("缺少appPassword"); } if (appKey != "myKey" && appPassword != "myPassword")//固定的appKey及appPassword,实际项目中应该来自数据库或配置文件 { throw new Exception("配置不存在"); } var key = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes(_configuration["JwtSecurityKey"])); var creds = new Microsoft.IdentityModel.Tokens.SigningCredentials(key, Microsoft.IdentityModel.Tokens.SecurityAlgorithms.HmacSha256); var claims = new List<System.Security.Claims.Claim>(); claims.Add(new System.Security.Claims.Claim("appKey", appKey));//仅在Token中记录appKey var token = new System.IdentityModel.Tokens.Jwt.JwtSecurityToken( issuer: _configuration["JwtTokenIssuer"], audience: _configuration["JwtTokenAudience"], claims: claims, expires: DateTime.Now.AddMinutes(30), signingCredentials: creds); return Ok(new Models.ApiResponse { status = 1, message = "OK", data = new System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler().WriteToken(token) }); } catch(Exception ex) { return Ok(new Models.ApiResponse { status = 0, message = ex.Message, data = "" }); } } // /api/token/delete public IActionResult Delete(string token) { //code: 加入黑名单,使其无效 return Ok(new Models.ApiResponse { status = 1, message = "OK", data = "" }); } } } TokenController.cs
UsersController.cs
Controllers目录下的UsersController.cs控制器文件,继承ApiBase.cs,作为数据调用示例。
该控制器定义了对User对象常规的明细、列表、录入、修改、删除等操作。
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; namespace Jwt.Gateway.Controllers { [Produces("application/json")] [Route("api/[controller]/[action]")] public class UsersController : ApiBase { /* * 1.要访问访问该控制器提供的接口请先通过"/api/token/get"获取token * 2.访问该控制器提供的接口http请求头必须具有值为"Bearer+空格+token"的Authorization键,格式参考: * "Authorization"="Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiQXBwIiwiYXBwS2V5IjoibXlLZXkiLCJleHAiOjE1NTE3ODc2MDMsImlzcyI6IkdhdGV3YXkiLCJhdWQiOiJhdWRpZW5jZSJ9.gQ9_Q7HUT31oFyfl533T-bNO5IWD2drl0NmD1JwQkMI" */ /// <summary> /// 临时用户测试数据,实际项目中应该来自数据库等媒介 /// </summary> static List<Models.User> _Users = null; static object _Lock = new object(); public UsersController() { if (_Users == null) { lock (_Lock) { if (_Users == null) { _Users = new List<Models.User>(); var now = DateTime.Now; for(var i = 0; i < 10; i++) { var num = i + 1; _Users.Add(new Models.User { UserId = num, UserName = "name"+num, UserPassword = "pwd"+num, UserJoinTime = now }); } } } } } // /api/users/detail [ApiActionFilter("用户明细")] public IActionResult Detail(long userId) { /* //获取appKey(在ApiBase中写入) var appKey = CurrentAppKey; //获取使用的权限(在ApiActionAuthorizeAttribute中写入) var permissions = HttpContext.Items["Permissions"]; */ var user = _Users.Find(o => o.UserId == userId); if (user == null) { throw new Exception("用户不存在"); } return Ok(new Models.ApiResponse { data = user, status = 1, message = "OK" }); } // /api/users/list [ApiActionFilter("用户列表")] public IActionResult List(int page, int size) { page = page < 1 ? 1 : page; size = size < 1 ? 1 : size; var total = _Users.Count(); var pages = total % size == 0 ? total / size : ((long)Math.Floor((double)total / size + 1)); if (page > pages) { return Ok(new Models.ApiResponse { data = new List<Models.User>(), status = 1, message = "OK", total = total }); } var li = new List<Models.User>(); var startIndex = page * size - size; var endIndex = startIndex + size - 1; if (endIndex > total - 1) { endIndex = total - 1; } for(; startIndex <= endIndex; startIndex++) { li.Add(_Users[startIndex]); } return Ok(new Models.ApiResponse { data = li, status = 1, message = "OK", total = total }); } // /api/users/add [ApiActionFilter("用户录入")] public IActionResult Add() { return Ok(new Models.ApiResponse { status = 1, message = "OK" }); } // /api/users/update [ApiActionFilter(new string[] { "用户修改", "用户录入", "用户删除" },ApiActionFilterAttributeOption.AND)] public IActionResult Update() { return Ok(new Models.ApiResponse { status = 1, message = "OK" }); } // /api/users/delete [ApiActionFilter("用户删除")] public IActionResult Delete() { return Ok(new Models.ApiResponse { status = 1, message = "OK" }); } } } UsersController.cs
ApiCustomException.cs
MiddleWares目录下的ApiCustomException.cs文件,是一个数据接口的统一异常处理中间件。
该文件整理并抄袭自:https://www.cnblogs.com/ShenNan/p/10197231.html
在此特别感谢一下作者的先行贡献,并请原谅我无耻的抄袭。
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; namespace Jwt.Gateway.MiddleWares { //参考: https://www.cnblogs.com/ShenNan/p/10197231.html public enum ApiCustomExceptionHandleType { JsonHandle = 0, PageHandle = 1, Both = 2 } public class ApiCustomExceptionMiddleWareOption { public ApiCustomExceptionMiddleWareOption( ApiCustomExceptionHandleType handleType = ApiCustomExceptionHandleType.JsonHandle, IList<PathString> jsonHandleUrlKeys = null, string errorHandingPath = "") { HandleType = handleType; JsonHandleUrlKeys = jsonHandleUrlKeys; ErrorHandingPath = errorHandingPath; } public ApiCustomExceptionHandleType HandleType { get; set; } public IList<PathString> JsonHandleUrlKeys { get; set; } public PathString ErrorHandingPath { get; set; } } public class ApiCustomExceptionMiddleWare { private RequestDelegate _next; private ApiCustomExceptionMiddleWareOption _option; private IDictionary<int, string> _exceptionStatusCodeDic; public ApiCustomExceptionMiddleWare(RequestDelegate next, ApiCustomExceptionMiddleWareOption option) { _next = next; _option = option; _exceptionStatusCodeDic = new Dictionary<int, string> { { 401, "未授权的请求" }, { 404, "找不到该页面" }, { 403, "访问被拒绝" }, { 500, "服务器发生意外的错误" } //其余状态自行扩展 }; } public async Task Invoke(HttpContext context) { Exception exception = null; try { await _next(context); } catch (Exception ex) { context.Response.Clear(); context.Response.StatusCode = 200;//手动设置状态码(总是成功) exception = ex; } finally { if (_exceptionStatusCodeDic.ContainsKey(context.Response.StatusCode) && !context.Items.ContainsKey("ExceptionHandled")) { var errorMsg = string.Empty; if (context.Response.StatusCode == 500 && exception != null) { errorMsg = $"{_exceptionStatusCodeDic[context.Response.StatusCode]}\r\n{(exception.InnerException != null ? exception.InnerException.Message : exception.Message)}"; } else { errorMsg = _exceptionStatusCodeDic[context.Response.StatusCode]; } exception = new Exception(errorMsg); } if (exception != null) { var handleType = _option.HandleType; if (handleType == ApiCustomExceptionHandleType.Both) { var requestPath = context.Request.Path; handleType = _option.JsonHandleUrlKeys != null && _option.JsonHandleUrlKeys.Count( k => requestPath.StartsWithSegments(k, StringComparison.CurrentCultureIgnoreCase)) > 0 ? ApiCustomExceptionHandleType.JsonHandle : ApiCustomExceptionHandleType.PageHandle; } if (handleType == ApiCustomExceptionHandleType.JsonHandle) await JsonHandle(context, exception); else await PageHandle(context, exception, _option.ErrorHandingPath); } } } private Jwt.Gateway.Models.ApiResponse GetApiResponse(Exception ex) { return new Jwt.Gateway.Models.ApiResponse() { status = 0, message = ex.Message }; } private async Task JsonHandle(HttpContext context, Exception ex) { var apiResponse = GetApiResponse(ex); var serialzeStr = Newtonsoft.Json.JsonConvert.SerializeObject(apiResponse); context.Response.ContentType = "application/json"; await context.Response.WriteAsync(serialzeStr, System.Text.Encoding.UTF8); } private async Task PageHandle(HttpContext context, Exception ex, PathString path) { context.Items.Add("Exception", ex); var originPath = context.Request.Path; context.Request.Path = path; try { await _next(context); } catch { } finally { context.Request.Path = originPath; } } } public static class ApiCustomExceptionMiddleWareExtensions { public static IApplicationBuilder UseApiCustomException(this IApplicationBuilder app, ApiCustomExceptionMiddleWareOption option) { return app.UseMiddleware<ApiCustomExceptionMiddleWare>(option); } } } ApiCustomException.cs
配置相关
appsettings.json
算法'HS256'要求SecurityKey.KeySize大于'128'位,所以JwtSecurityKey可不要太短了哦。
{ "Urls": "http://localhost:60000", "AllowedHosts": "*", "JwtSecurityKey": "areyouokhhhhhhhhhhhhhhhhhhhhhhhhhhh", "JwtTokenIssuer": "Jwt.Gateway", "JwtTokenAudience": "App" } appsettings.json
Startup.cs
关于JWT的配置可以在通过JwtBearerOptions加入一些自己的事件处理逻辑,共有4个事件可供调用:
OnAuthenticationFailed,OnMessageReceived,OnTokenValidated,OnChallenge, 本示例中是在OnTokenValidated中插入Token黑名单的校验逻辑。黑名单应该是Jwt应用场景中主动使Token过期的主流做法了。
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Jwt.Gateway.MiddleWares; using Microsoft.Extensions.DependencyInjection; namespace Jwt.Gateway { public class Startup { private readonly Microsoft.Extensions.Configuration.IConfiguration _configuration; public Startup(Microsoft.Extensions.Configuration.IConfiguration configuration) { _configuration = configuration; } public void ConfigureServices(IServiceCollection services) { services.AddAuthentication(Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.Events = new Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerEvents { /*OnMessageReceived = context => { context.Token = context.Request.Query["access_token"]; return Task.CompletedTask; },*/ OnTokenValidated = context => { var token = ((System.IdentityModel.Tokens.Jwt.JwtSecurityToken)context.SecurityToken).RawData; if (InBlacklist(token)) { context.Fail("token in blacklist"); } return Task.CompletedTask; } }; options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidAudience = _configuration["JwtTokenAudience"], ValidIssuer = _configuration["JwtTokenIssuer"], IssuerSigningKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes(_configuration["JwtSecurityKey"])) }; }); services.AddMvc().AddJsonOptions(option=> { option.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss.fff"; }); } public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseApiCustomException(new ApiCustomExceptionMiddleWareOption( handleType: ApiCustomExceptionHandleType.Both, jsonHandleUrlKeys: new PathString[] { "/api" }, errorHandingPath: "/home/error")); app.UseAuthentication(); app.UseMvc(); } bool InBlacklist(string token) { //code: 实际项目中应该查询数据库或配置文件进行比对 return false; } } } Startup.cs
Program.cs
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; namespace Jwt.Gateway { public class Program { public static void Main(string[] args) { BuildWebHost(args).Run(); } public static IWebHost BuildWebHost(string[] args) { var config = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json", optional: true) .Build(); return WebHost.CreateDefaultBuilder(args) .UseKestrel() .UseConfiguration(config) .UseStartup<Startup>() .Build(); } } } Program.cs
运行截图
[运行截图-获取Token]
[运行截图-配置Fiddler调用接口获取数据]
[运行截图-获取到数据]
如果Token校验失败将会返回401错误!
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对猪先飞的支持。
相关文章
浅谈Spring Cloud Netflix-Ribbon灰度方案之Zuul网关灰度
这篇文章主要介绍了浅谈Spring Cloud Netflix-Ribbon灰度方案之Zuul网关灰度,想了解Ribbon灰度的同学可以参考下...2021-04-09手机未实名认证被停机了怎么办?中国移动/联通/电信手机号实名认证方法
,“手机实名制”就是每一个手机号码对应一个身份证,对应唯一真实的主人。如果不认证可能会陆续遭到停机,这该怎么办呢?手机怎么认证呢?下面就详情来看看移动联通电信手机号实名认证方式吧...2016-11-01- 这篇文章主要介绍了asp.net core MVC之实现基于token的认证,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-05-07
关于C#.net winform程序验证moss的集成身份认证实例
因为网站使用的是windows集成认证,所以遇到了权限问题,需要输入密码。使操作和用户体验非常不方便,研究了好久没有找到好的方法,最后终于让我踏破铁鞋总结出了下面的方法...2020-06-25- 这篇文章主要介绍了ASP.NET Core使用JWT认证授权的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-09-22
Nginx上配置Basic Authorization登录认服务证的教程
现在我们所使用的包括社交网络API等开放平台授权获得用户的用户名和密码一般有两种认证方式,一种是Basic Auth,一种是OAuth,这里我们就来看一下Nginx上配置Basic Authorization登录认服务证的教程...2016-08-27- 这篇文章主要给大家介绍了关于ASP.NET Core学习之使用JWT认证授权的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用ASP.NET Core具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧...2021-09-22
.net core webapi jwt 更为清爽的认证详解
这篇文章主要介绍了.net core webapi jwt 更为清爽的认证详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2021-09-22winform C#获得Mac地址,IP地址,子网掩码,默认网关的实例
下面小编就为大家带来一篇winform C#获得Mac地址,IP地址,子网掩码,默认网关的实例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2020-06-25- 首先用htpasswd创建一个密码文件:比如文件名叫做my.passwd /home/apache/bin/htpasswd -c -b my.passwd myusername mypassword 如果增加帐号: /home/apache/bin/htpasswd...2016-01-28
- 这篇文章主要介绍了JWT+Log4net配置与使用详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2021-09-22
- 这篇文章主要给大家介绍了关于.NET core 3.0如何使用Jwt保护api的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用.NET core 3.0具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧...2021-09-22
- 这篇文章主要介绍了Springboot shiro认证授权实现原理及实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-06-11
- 这篇文章主要给大家介绍了关于JWT + ASP.NET MVC时间戳防止重放攻击发的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-09-22
- MongoDB是基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。默认情况下,MongoDB实例启动运行时是没有启用用户访问权限控制的,在实例本机服务器上都可以随意连接到实例进行各种操作,MongoDB不会对连接客户端进行用户验证...2021-06-26
- Nginx超级强大它可以单独为一个域名设置用户认证,方法也很简单我们只要生成用户认证的用户名和密码,然后再Nginx添加auth认证配置即可...2016-01-27
- Visual Studio 2015 Preview 除了给我们带了了C# 6.0的新语法、跨移动的开发以外,还给我们带来了ASP.NET5(也就是之前被称作下一代ASP.NET的ASP.NET vNext)。本文给大家介绍asp.net5中的用户认证与授权(1),需要的朋友可以参考下...2021-09-22
- 这篇文章主要介绍了如何利用go-zero在Go中快速实现JWT认证,本文分步骤通过实例图文相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧...2020-10-26
- JWT全称是json web token,它将用户信息加密到 token 里,服务器不保存任何用户信息,服务器通过使用保存的密钥验证 token 的正确性,只要正确即通过验证,这篇文章主要给大家介绍了关于SpringBoot整合JWT的相关资料,需要的朋友可以参考下...2021-06-29
- 这篇文章主要介绍了python-jwt用户认证食用教学的实现方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-01-19