Asp.Net Core基于JWT认证的数据接口网关Demo

原文: Asp.Net Core基于JWT认证的数据接口网关Demo

近日,应一位朋友的邀请写了个Asp.Net Core基于JWT认证的数据接口网关Demo。朋友自己开了个公司,接到的一个升级项目,客户要求用Aps.Net Core做数据网关服务且基于JWT认证实现对前后端分离的数据服务支持,于是想到我一直做.Net开发,问我是否对.Net Core有所了解?能不能做个简单Demo出来看看?我说,分道扬镳之后我不是调用别人的接口就是提供接口给别人调用,于是便有了以下示例代码。

示例要求能演示获取Token及如何使用该Token访问数据资源,在Demo中实现了JWT的颁发及验证以及重写一个ActionAuthorizeAttribute实现对具体数据接口的调用权限控制,先看一下项目截图:

项目截图

[项目截图]

项目文件介绍

解决方案下只有一个项目,项目名称就叫Jwt.Gateway,包含主要文件有:

  1. Controllers目录下的ApiActionFilterAttribute.cs文件,继承Microsoft.AspNetCore.Mvc.Filters.ActionFilterAttribute,用于校验接口调用者对具体接口的访问权限。
  2. Controllers目录下的ApiBase.cs文件,继承Microsoft.AspNetCore.Mvc.Controller,具有Microsoft.AspNetCore.Authorization.Authorize特性引用,用于让所有数据接口用途的控制器继承,定义有CurrentAppKey属性(来访应用程序的身份标识)并在OnActionExecuting事件中统一分析Claims并赋值。
  3. Controllers目录下的TokenController.cs控制器文件,用于对调用方应用程序获取及注销Token。
  4. Controllers目录下的UsersController.cs控制器文件,继承ApiBase.cs,作为数据调用示例。
  5. MiddleWares目录下的ApiCustomException.cs文件,是一个数据接口的统一异常处理中间件。
  6. Models目录下的ApiResponse.cs文件,用于做数据接口的统一数据及错误信息输出实体模型。
  7. Models目录下的User.cs文件,示例数据实体模型。
  8. Program.csStartup.cs文件就不介绍了,随便建个空项目都有。

项目文件代码

ApiActionFilterAttribute.cs

Controllers目录下的ApiActionFilterAttribute.cs文件,继承Microsoft.AspNetCore.Mvc.Filters.ActionFilterAttribute,用于校验接口调用者对具体接口的访问权限。

设想每一个到访的请求都是一个应用程序,每一个应用程序都分配有基本的Key和Password,每一个应用程序具有不同的接口访问权限,所以在具体的数据接口上应该声明该接口所要求的权限值,比如修改用户信息的接口应该在接口方法上声明需要具有“修改用户”的权限,用例:[ApiActionFilter("用户修改")]

大部分情况下一个接口(方法)对应一个操作,这样基本上就能应付了,但是不排除有时候可能需要多个权限组合进行验证,所以该文件中有一个对多个权限值进行校验的“”和“”枚举,用例:[ApiActionFilter(new string[] { "用户修改","用户录入","用户删除" },ApiActionFilterAttributeOption.AND)],这样好像就差不多了。

由于在一个接口调用之后可能需要将该接口所声明需要的权限值记入日志等需求,因此权限值集合将被写入到HttpContext.Items["Permissions"]中以方便可能的后续操作访问,看代码:

分享图片

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Threading.Tasks;
 5 using Microsoft.AspNetCore.Mvc.Filters;
 6 
 7 namespace Jwt.Gateway.Controllers
 8 {
 9     public enum ApiActionFilterAttributeOption
10     {
11         OR,AND
12     }
13     public class ApiActionFilterAttribute : Microsoft.AspNetCore.Mvc.Filters.ActionFilterAttribute
14     {
15         List<string> Permissions = new List<string>();
16         ApiActionFilterAttributeOption Option = ApiActionFilterAttributeOption.AND;
17         public ApiActionFilterAttribute(string permission)
18         {
19             Permissions.Add(permission);
20         }
21         public ApiActionFilterAttribute(string[] permissions,ApiActionFilterAttributeOption option)
22         {
23             foreach(var permission in permissions) {
24                 if (Permissions.Contains(permission))
25                 {
26                     continue;
27                 }
28                 Permissions.Add(permission);
29             }
30             Option = option;
31         }
32 
33         public override void OnActionExecuting(ActionExecutingContext context)
34         {
35             var key = GetAppKey(context);
36             List<string> keyPermissions = GetAppKeyPermissions(key);
37             var isAnd = Option == ApiActionFilterAttributeOption.AND;
38             var permissionsCount = Permissions.Count;
39             var keyPermissionsCount = keyPermissions.Count;
40             for (var i = 0; i < permissionsCount; i++)
41             {
42                 bool flag = false;
43                 for (var j = 0; j < keyPermissions.Count; j++)
44                 {
45                     if (flag = string.Equals(Permissions[i],keyPermissions[j],StringComparison.OrdinalIgnoreCase))
46                     {
47                         break;
48                     }
49                 }
50                 if (flag)
51                 {
52                     continue;
53                 }
54                 if (isAnd)
55                 {
56                     throw new Exception("应用“" + key + "”缺少“" + Permissions[i] + "”的权限");
57                 }
58             }
59 
60             context.HttpContext.Items.Add("Permissions",Permissions);
61 
62             base.OnActionExecuting(context);
63         }
64 
65         private string GetAppKey(ActionExecutingContext context)
66         {
67             var claims = context.HttpContext.User.Claims;
68             if (claims == null)
69             {
70                 throw new Exception("未能获取到应用标识");
71             }
72             var claimKey = claims.ToList().Find(o => string.Equals(o.Type,"AppKey",StringComparison.OrdinalIgnoreCase));
73             if (claimKey == null)
74             {
75                 throw new Exception("未能获取到应用标识");
76             }
77 
78             return claimKey.Value;
79         }
80         private List<string> GetAppKeyPermissions(string appKey)
81         {
82             List<string> li = new List<string>
83             {
84                 "用户明细","用户列表","用户录入","用户修改","用户删除"
85             };
86             return li;
87         }
88 
89     }
90 }
ApiActionAuthorizeAttribute.cs

ApiBase.cs

Controllers目录下的ApiBase.cs文件,继承Microsoft.AspNetCore.Mvc.Controller,具有Microsoft.AspNetCore.Authorization.Authorize特性引用,用于让所有数据接口用途的控制器继承,定义有CurrentAppKey属性(来访应用程序的身份标识)并在OnActionExecuting事件中统一分析Claims并赋值。

通过验证之后,Aps.Net Core会在HttpContext.User.Claims中将将来访者的身份信息记录下来,我们可以通过该集合得到来访者的身份信息。

分享图片

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Threading.Tasks;
 5 using Microsoft.AspNetCore.Http;
 6 using Microsoft.AspNetCore.Mvc;
 7 using Microsoft.AspNetCore.Mvc.Filters;
 8 
 9 namespace Jwt.Gateway.Controllers
10 {
11     [Microsoft.AspNetCore.Authorization.Authorize]
12     public class ApiBase : Microsoft.AspNetCore.Mvc.Controller
13     {
14         private string _CurrentAppKey = "";
15         public string CurrentAppKey { get { return _CurrentAppKey; } }
16         public override void OnActionExecuting(ActionExecutingContext context)
17         {
18             var claims = context.HttpContext.User.Claims.ToList();
19             var claim = claims.Find(o => o.Type == "appKey");
20             if (claim == null)
21             {
22                 throw new Exception("未通过认证");
23             }
24             var appKey = claim.Value;
25             if (string.IsNullOrEmpty(appKey))
26             {
27                 throw new Exception("appKey不合法");
28             }
29 
30             _CurrentAppKey = appKey;
31 
32             base.OnActionExecuting(context);
33         }
34     }
35 }
ApiBase.cs

TokenController.cs

Controllers目录下的TokenController.cs控制器文件,用于对调用方应用程序获取及注销Token。

分享图片

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Threading.Tasks;
 5 using Microsoft.AspNetCore.Http;
 6 using Microsoft.AspNetCore.Mvc;
 7 
 8 namespace Jwt.Gateway.Controllers
 9 {
10     [Route("api/[controller]/[action]")]
11     public class TokenController : Controller
12     {
13         private readonly Microsoft.Extensions.Configuration.IConfiguration _configuration;
14 
15         public TokenController(Microsoft.Extensions.Configuration.IConfiguration configuration)
16         {
17             _configuration = configuration;
18         }
19 
20         // /api/token/get
21         public IActionResult Get(string appKey,string appPassword)
22         {
23             try
24             {
25                 if (string.IsNullOrEmpty(appKey))
26                 {
27                     throw new Exception("缺少appKey");
28                 }
29                 if (string.IsNullOrEmpty(appKey))
30                 {
31                     throw new Exception("缺少appPassword");
32                 }
33                 if (appKey != "myKey" && appPassword != "myPassword")//固定的appKey及appPassword,实际项目中应该来自数据库或配置文件
34                 {
35                     throw new Exception("配置不存在");
36                 }
37 
38                 var key = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes(_configuration["JwtSecurityKey"]));
39                 var creds = new Microsoft.IdentityModel.Tokens.SigningCredentials(key,Microsoft.IdentityModel.Tokens.SecurityAlgorithms.HmacSha256);
40                 var claims = new List<System.Security.Claims.Claim>();
41                 claims.Add(new System.Security.Claims.Claim("appKey",appKey));//仅在Token中记录appKey
42                 var token = new System.IdentityModel.Tokens.Jwt.JwtSecurityToken(
43                         issuer: _configuration["JwtTokenIssuer"],44                         audience: _configuration["JwtTokenAudience"],45                         claims: claims,46                         expires: DateTime.Now.AddMinutes(30),47                         signingCredentials: creds);
48 
49                 return Ok(new Models.ApiResponse { status = 1,message = "OK",data = new System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler().WriteToken(token) });
50 
51             }
52             catch(Exception ex)
53             {
54                 return Ok(new Models.ApiResponse { status = 0,message = ex.Message,data = "" });
55             }
56         }
57         
58         // /api/token/delete
59         public IActionResult Delete(string token)
60         {
61             //code: 加入黑名单,使其无效
62 
63             return Ok(new Models.ApiResponse { status = 1,data = "" });
64         }
65 
66 
67     }
68 }
TokenController.cs

UsersController.cs

Controllers目录下的UsersController.cs控制器文件,继承ApiBase.cs,作为数据调用示例。

该控制器定义了对User对象常规的 明细列表录入修改删除 等操作。

分享图片

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Threading.Tasks;
  5 using Microsoft.AspNetCore.Mvc;
  6 
  7 namespace Jwt.Gateway.Controllers
  8 {
  9     [Produces("application/json")]
 10     [Route("api/[controller]/[action]")]
 11     public class UsersController : ApiBase
 12     {
 13         /* 
 14          * 1.要访问访问该控制器提供的接口请先通过"/api/token/get"获取token
 15          * 2.访问该控制器提供的接口http请求头必须具有值为"Bearer+空格+token"的Authorization键,格式参考:
 16          *   "Authorization"="Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiQXBwIiwiYXBwS2V5IjoibXlLZXkiLCJleHAiOjE1NTE3ODc2MDMsImlzcyI6IkdhdGV3YXkiLCJhdWQiOiJhdWRpZW5jZSJ9.gQ9_Q7HUT31oFyfl533T-bNO5IWD2drl0NmD1JwQkMI"
 17         */
 18 
 19         /// <summary>
 20         /// 临时用户测试数据,实际项目中应该来自数据库等媒介
 21         /// </summary>
 22         static List<Models.User> _Users = null;
 23         static object _Lock = new object();
 24         public UsersController()
 25         {
 26             if (_Users == null)
 27             {
 28                 lock (_Lock)
 29                 {
 30                     if (_Users == null)
 31                     {
 32                         _Users = new List<Models.User>();
 33                         var now = DateTime.Now;
 34                         for(var i = 0; i < 10; i++)
 35                         {
 36                             var num = i + 1;
 37                             _Users.Add(new Models.User { UserId = num,UserName = "name"+num,UserPassword = "pwd"+num,UserJoinTime = now });
 38                         }
 39                     }
 40                 }
 41             }
 42         }
 43 
 44         // /api/users/detail
 45         [ApiActionFilter("用户明细")]
 46         public IActionResult Detail(long userId)
 47         {
 48             /*
 49             //获取appKey(在ApiBase中写入)
 50             var appKey = CurrentAppKey;
 51             //获取使用的权限(在ApiActionAuthorizeAttribute中写入)
 52             var permissions = HttpContext.Items["Permissions"];
 53             */
 54 
 55             var user = _Users.Find(o => o.UserId == userId);
 56             if (user == null)
 57             {
 58                 throw new Exception("用户不存在");
 59             }
 60 
 61             return Ok(new Models.ApiResponse { data = user,status = 1,message = "OK" });
 62         }
 63 
 64         // /api/users/list
 65         [ApiActionFilter("用户列表")]
 66         public IActionResult List(int page,int size)
 67         {
 68             page = page < 1 ? 1 : page;
 69             size = size < 1 ? 1 : size;
 70             var total = _Users.Count();
 71             var pages = total % size == 0 ? total / size : ((long)Math.Floor((double)total / size + 1));
 72             if (page > pages)
 73             {
 74                 return Ok(new Models.ApiResponse { data = new List<Models.User>(),total = total });
 75             }
 76             var li = new List<Models.User>();
 77             var startIndex = page * size - size;
 78             var endIndex = startIndex + size - 1;
 79             if (endIndex > total - 1)
 80             {
 81                 endIndex = total - 1;
 82             }
 83             for(; startIndex <= endIndex; startIndex++)
 84             {
 85                 li.Add(_Users[startIndex]);
 86             }
 87             return Ok(new Models.ApiResponse { data = li,total = total });
 88         }
 89 
 90         // /api/users/add
 91         [ApiActionFilter("用户录入")]
 92         public IActionResult Add()
 93         {
 94             return Ok(new Models.ApiResponse { status = 1,message = "OK" });
 95         }
 96 
 97         // /api/users/update
 98         [ApiActionFilter(new string[] { "用户修改","用户删除" },ApiActionFilterAttributeOption.AND)]
 99         public IActionResult Update()
100         {
101             return Ok(new Models.ApiResponse { status = 1,message = "OK" });
102         }
103 
104         // /api/users/delete
105         [ApiActionFilter("用户删除")]
106         public IActionResult Delete()
107         {
108             return Ok(new Models.ApiResponse { status = 1,message = "OK" });
109         }
110     }
111 }
UsersController.cs

ApiCustomException.cs

MiddleWares目录下的ApiCustomException.cs文件,是一个数据接口的统一异常处理中间件。

该文件整理并抄袭自:https://www.cnblogs.com/ShenNan/p/10197231.html

在此特别感谢一下作者的先行贡献,并请原谅我无耻的抄袭。

分享图片

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Threading.Tasks;
  5 using Microsoft.AspNetCore.Http;
  6 using Microsoft.AspNetCore.Builder;
  7 using Microsoft.Extensions.DependencyInjection;
  8 
  9 namespace Jwt.Gateway.MiddleWares
 10 {
 11     //参考: https://www.cnblogs.com/ShenNan/p/10197231.html
 12 
 13     public enum ApiCustomExceptionHandleType
 14     {
 15         JsonHandle = 0, 16         PageHandle = 1, 17         Both = 2
 18     }
 19     public class ApiCustomExceptionMiddleWareOption
 20     {
 21         public ApiCustomExceptionMiddleWareOption(
 22             ApiCustomExceptionHandleType handleType = ApiCustomExceptionHandleType.JsonHandle, 23             IList<PathString> jsonHandleUrlKeys = null, 24             string errorHandingPath = "")
 25         {
 26             HandleType = handleType;
 27             JsonHandleUrlKeys = jsonHandleUrlKeys;
 28             ErrorHandingPath = errorHandingPath;
 29         }
 30         public ApiCustomExceptionHandleType HandleType { get; set; }
 31         public IList<PathString> JsonHandleUrlKeys { get; set; }
 32         public PathString ErrorHandingPath { get; set; }
 33     }
 34     public class ApiCustomExceptionMiddleWare
 35     {
 36         private RequestDelegate _next;
 37         private ApiCustomExceptionMiddleWareOption _option;
 38         private IDictionary<int,string> _exceptionStatusCodeDic;
 39 
 40         public ApiCustomExceptionMiddleWare(RequestDelegate next,ApiCustomExceptionMiddleWareOption option)
 41         {
 42             _next = next;
 43             _option = option;
 44             _exceptionStatusCodeDic = new Dictionary<int,string>
 45             {
 46                 { 401,"未授权的请求" }, 47                 { 404,"找不到该页面" }, 48                 { 403,"访问被拒绝" }, 49                 { 500,"服务器发生意外的错误" }
 50                 //其余状态自行扩展
 51             };
 52         }
 53 
 54         public async Task Invoke(HttpContext context)
 55         {
 56             Exception exception = null;
 57             try
 58             {
 59                 await _next(context);
 60             }
 61             catch (Exception ex)
 62             {
 63                 context.Response.Clear();
 64                 context.Response.StatusCode = 200;//手动设置状态码(总是成功)
 65                 exception = ex;
 66             }
 67             finally
 68             {
 69                 if (_exceptionStatusCodeDic.ContainsKey(context.Response.StatusCode) &&
 70                     !context.Items.ContainsKey("ExceptionHandled"))
 71                 {
 72                     var errorMsg = string.Empty;
 73                     if (context.Response.StatusCode == 500 && exception != null)
 74                     {
 75                         errorMsg = $"{_exceptionStatusCodeDic[context.Response.StatusCode]}\r\n{(exception.InnerException != null ? exception.InnerException.Message : exception.Message)}";
 76                     }
 77                     else
 78                     {
 79                         errorMsg = _exceptionStatusCodeDic[context.Response.StatusCode];
 80                     }
 81                     exception = new Exception(errorMsg);
 82                 }
 83                 if (exception != null)
 84                 {
 85                     var handleType = _option.HandleType;
 86                     if (handleType == ApiCustomExceptionHandleType.Both)
 87                     {
 88                         var requestPath = context.Request.Path;
 89                         handleType = _option.JsonHandleUrlKeys != null && _option.JsonHandleUrlKeys.Count(
 90                             k => requestPath.StartsWithSegments(k,StringComparison.CurrentCultureIgnoreCase)) > 0 ?
 91                             ApiCustomExceptionHandleType.JsonHandle :
 92                             ApiCustomExceptionHandleType.PageHandle;
 93                     }
 94 
 95                     if (handleType == ApiCustomExceptionHandleType.JsonHandle)
 96                         await JsonHandle(context,exception);
 97                     else
 98                         await PageHandle(context,exception,_option.ErrorHandingPath);
 99                 }
100             }
101         }
102         private Jwt.Gateway.Models.ApiResponse GetApiResponse(Exception ex)
103         {
104             return new Jwt.Gateway.Models.ApiResponse() { status = 0,message = ex.Message };
105         }
106         private async Task JsonHandle(HttpContext context,Exception ex)
107         {
108             var apiResponse = GetApiResponse(ex);
109             var serialzeStr = Newtonsoft.Json.JsonConvert.SerializeObject(apiResponse);
110             context.Response.ContentType = "application/json";
111             await context.Response.WriteAsync(serialzeStr,System.Text.Encoding.UTF8);
112         }
113         private async Task PageHandle(HttpContext context,Exception ex,PathString path)
114         {
115             context.Items.Add("Exception",ex);
116             var originPath = context.Request.Path;
117             context.Request.Path = path;
118             try
119             {
120                 await _next(context);
121             }
122             catch { }
123             finally
124             {
125                 context.Request.Path = originPath;
126             }
127         }
128     }
129     public static class ApiCustomExceptionMiddleWareExtensions
130     {
131         public static IApplicationBuilder UseApiCustomException(this IApplicationBuilder app,ApiCustomExceptionMiddleWareOption option)
132         {
133             return app.UseMiddleware<ApiCustomExceptionMiddleWare>(option);
134         }
135     }
136 }
ApiCustomException.cs

配置相关

appsettings.json

算法‘HS256‘要求SecurityKey.KeySize大于‘128‘位,所以JwtSecurityKey可不要太短了哦。

分享图片

1 {
2   "Urls": "http://localhost:60000",3   "AllowedHosts": "*",4   "JwtSecurityKey": "areyouokhhhhhhhhhhhhhhhhhhhhhhhhhhh",5   "JwtTokenIssuer": "Jwt.Gateway",6   "JwtTokenAudience": "App"
7 }
appsettings.json

Startup.cs

关于JWT的配置可以在通过JwtBearerOptions加入一些自己的事件处理逻辑,共有4个事件可供调用:OnAuthenticationFailed,OnMessageReceived,OnTokenValidated,OnChallenge,本示例中是在OnTokenValidated中插入Token黑名单的校验逻辑。黑名单应该是Jwt应用场景中主动使Token过期的主流做法了。

分享图片

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Threading.Tasks;
 5 using Microsoft.AspNetCore.Builder;
 6 using Microsoft.AspNetCore.Hosting;
 7 using Microsoft.AspNetCore.Http;
 8 using Jwt.Gateway.MiddleWares;
 9 using Microsoft.Extensions.DependencyInjection;
10 
11 namespace Jwt.Gateway
12 {
13     public class Startup
14     {
15         private readonly Microsoft.Extensions.Configuration.IConfiguration _configuration;
16 
17         public Startup(Microsoft.Extensions.Configuration.IConfiguration configuration)
18         {
19             _configuration = configuration;
20         }
21         
22         public void ConfigureServices(IServiceCollection services)
23         {
24             services.AddAuthentication(Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerDefaults.AuthenticationScheme)
25                 .AddJwtBearer(options => {
26                     options.Events = new Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerEvents
27                     {
28                         /*OnMessageReceived = context =>
29                         {
30                             context.Token = context.Request.Query["access_token"];
31                             return Task.CompletedTask;
32                         },*/
33                         OnTokenValidated = context =>
34                         {
35                             var token = ((System.IdentityModel.Tokens.Jwt.JwtSecurityToken)context.SecurityToken).RawData;
36                             if (InBlacklist(token))
37                             {
38                                 context.Fail("token in blacklist");
39                             }
40                             return Task.CompletedTask;
41                         }
42                     };
43                     options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
44                     {
45                         ValidateIssuer = true,46                         ValidateAudience = true,47                         ValidateLifetime = true,48                         ValidateIssuerSigningKey = true,49                         ValidAudience = _configuration["JwtTokenAudience"],50                         ValidIssuer = _configuration["JwtTokenIssuer"],51                         IssuerSigningKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes(_configuration["JwtSecurityKey"]))
52                     };
53                 });
54             services.AddMvc().AddJsonOptions(option=> {
55                 option.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss.fff";
56             });
57         }
58 
59         public void Configure(IApplicationBuilder app,IHostingEnvironment env)
60         {
61             if (env.IsDevelopment())
62             {
63                 app.UseDeveloperExceptionPage();
64             }
65 
66             app.UseApiCustomException(new ApiCustomExceptionMiddleWareOption(
67                      handleType: ApiCustomExceptionHandleType.Both,68                      jsonHandleUrlKeys: new PathString[] { "/api" },69                      errorHandingPath: "/home/error"));
70 
71             app.UseAuthentication();
72 
73             app.UseMvc();
74         }
75 
76 
77 
78         bool InBlacklist(string token)
79         {
80             //code: 实际项目中应该查询数据库或配置文件进行比对
81 
82             return false;
83         }
84 
85 
86     }
87 }
Startup.cs

Program.cs

分享图片

 1 using System;
 2 using System.Collections.Generic;
 3 using System.IO;
 4 using System.Linq;
 5 using System.Threading.Tasks;
 6 using Microsoft.AspNetCore;
 7 using Microsoft.AspNetCore.Hosting;
 8 using Microsoft.Extensions.Configuration;
 9 using Microsoft.Extensions.Logging;
10 
11 namespace Jwt.Gateway
12 {
13     public class Program
14     {
15         public static void Main(string[] args)
16         {
17             BuildWebHost(args).Run();
18         }
19 
20         public static IWebHost BuildWebHost(string[] args)
21         {
22             var config = new ConfigurationBuilder()
23                 .SetBasePath(Directory.GetCurrentDirectory())
24                 .AddJsonFile("appsettings.json",optional: true)
25                 .Build();
26 
27             return WebHost.CreateDefaultBuilder(args)
28                 .UseKestrel()
29                 .UseConfiguration(config)
30                 .UseStartup<Startup>()
31                 .Build();
32         }
33     }
34 }
Program.cs

运行截图

运行截图-获取Token

[运行截图-获取Token]

运行截图-配置Fiddler调用接口获取数据

[运行截图-配置Fiddler调用接口获取数据]

运行截图-获取到数据

[运行截图-获取到数据]

 

如果Token校验失败将会返回401错误!

 如果你发现有错误,请善意指出,谢谢!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


在上文中,我介绍了事件驱动型架构的一种简单的实现,并演示了一个完整的事件派发、订阅和处理的流程。这种实现太简单了,百十行代码就展示了一个基本工作原理。然而,要将这样的解决方案运用到实际生产环境,还有很长的路要走。今天,我们就研究一下在事件处理器中,对象生命周期的管理问题。事实上,不仅仅是在事件处理器
上文已经介绍了Identity Service的实现过程。今天我们继续,实现一个简单的Weather API和一个基于Ocelot的API网关。 回顾 《Angular SPA基于Ocelot API网关与IdentityServer4的身份认证与授权(一)》 Weather API Weather
最近我为我自己的应用开发框架Apworks设计了一套案例应用程序,并以Apache 2.0开源,开源地址是:https://github.com/daxnet/apworks-examples,目的是为了让大家更为方便地学习和使用.NET Core、最新的前端开发框架Angular,以及Apwork
HAL(Hypertext Application Language,超文本应用语言)是一种RESTful API的数据格式风格,为RESTful API的设计提供了接口规范,同时也降低了客户端与服务端接口的耦合度。很多当今流行的RESTful API开发框架,包括Spring REST,也都默认支
在前面两篇文章中,我详细介绍了基本事件系统的实现,包括事件派发和订阅、通过事件处理器执行上下文来解决对象生命周期问题,以及一个基于RabbitMQ的事件总线的实现。接下来对于事件驱动型架构的讨论,就需要结合一个实际的架构案例来进行分析。在领域驱动设计的讨论范畴,CQRS架构本身就是事件驱动的,因此,
HAL,全称为Hypertext Application Language,它是一种简单的数据格式,它能以一种简单、统一的形式,在API中引入超链接特性,使得API的可发现性(discoverable)更强,并具有自描述的特点。使用了HAL的API会更容易地被第三方开源库所调用,并且使用起来也很方便
何时使用领域驱动设计?其实当你的应用程序架构设计是面向业务的时候,你已经开始使用领域驱动设计了。领域驱动设计既不是架构风格(Architecture Style),也不是架构模式(Architecture Pattern),它也不是一种软件开发方法论,所以,是否应该使用领域驱动设计,以及什么时候使用
《在ASP.NET Core中使用Apworks快速开发数据服务》一文中,我介绍了如何使用Apworks框架的数据服务来快速构建用于查询和管理数据模型的RESTful API,通过该文的介绍,你会看到,使用Apworks框架开发数据服务是何等简单快捷,提供的功能也非常多,比如对Hypermedia的
在上一讲中,我们已经完成了一个完整的案例,在这个案例中,我们可以通过Angular单页面应用(SPA)进行登录,然后通过后端的Ocelot API网关整合IdentityServer4完成身份认证。在本讲中,我们会讨论在当前这种架构的应用程序中,如何完成用户授权。 回顾 《Angular SPA基于
Keycloak是一个功能强大的开源身份和访问管理系统,提供了一整套解决方案,包括用户认证、单点登录(SSO)、身份联合、用户注册、用户管理、角色映射、多因素认证和访问控制等。它广泛应用于企业和云服务,可以简化和统一不同应用程序和服务的安全管理,支持自托管或云部署,适用于需要安全、灵活且易于扩展的用
3月7日,微软发布了Visual Studio 2017 RTM,与之一起发布的还有.NET Core Runtime 1.1.0以及.NET Core SDK 1.0.0,尽管这些并不是最新版,但也已经从preview版本升级到了正式版。所以,在安装Visual Studio 2017时如果启用了
在上文中,我介绍了如何在Ocelot中使用自定义的中间件来修改下游服务的response body。今天,我们再扩展一下设计,让我们自己设计的中间件变得更为通用,使其能够应用在不同的Route上。比如,我们可以设计一个通用的替换response body的中间件,然后将其应用在多个Route上。 O
不少关注我博客的朋友都知道我在2009年左右开发过一个名为Apworks的企业级应用程序开发框架,旨在为分布式企业系统软件开发提供面向领域驱动(DDD)的框架级别的解决方案,并对多种系统架构风格提供支持。这个框架的开发和维护我坚持了很久,一直到2015年,我都一直在不停地重构这个项目。目前这个项目在
好吧,这个题目我也想了很久,不知道如何用最简单的几个字来概括这篇文章,原本打算取名《Angular单页面应用基于Ocelot API网关与IdentityServer4ʺSP.NET Identity实现身份认证与授权》,然而如你所见,这样的名字实在是太长了。所以,我不得不缩写“单页面应用”几个字
在前面两篇文章中,我介绍了基于IdentityServer4的一个Identity Service的实现,并且实现了一个Weather API和基于Ocelot的API网关,然后实现了通过Ocelot API网关整合Identity Service做身份认证的API请求。今天,我们进入前端开发,设计
Ocelot是ASP.NET Core下的API网关的一种实现,在微服务架构领域发挥了非常重要的作用。本文不会从整个微服务架构的角度来介绍Ocelot,而是介绍一下最近在学习过程中遇到的一个问题,以及如何使用中间件(Middleware)来解决这样的问题。 问题描述 在上文中,我介绍了一种在Angu
在大数据处理和人工智能时代,数据工厂(Data Factory)无疑是一个非常重要的大数据处理平台。市面上也有成熟的相关产品,比如Azure Data Factory,不仅功能强大,而且依托微软的云计算平台Azure,为大数据处理提供了强大的计算能力,让大数据处理变得更为稳定高效。由于工作中我的项目
在上文中,我们讨论了事件处理器中对象生命周期的问题,在进入新的讨论之前,首先让我们总结一下,我们已经实现了哪些内容。下面的类图描述了我们已经实现的组件及其之间的关系,貌似系统已经变得越来越复杂了。其中绿色的部分就是上文中新实现的部分,包括一个简单的Event Store,一个事件处理器执行上下文的接
在之前《在ASP.NET Core中使用Apworks快速开发数据服务》一文的评论部分,.NET大神张善友为我提了个建议,可以使用Compile As a Service的Roslyn为语法解析提供支持。在此非常感激友哥给我的建议,也让我了解了一些Roslyn的知识。使用Roslyn的一个很大的好处
很长一段时间以来,我都在思考如何在ASP.NET Core的框架下,实现一套完整的事件驱动型架构。这个问题看上去有点大,其实主要目标是为了实现一个基于ASP.NET Core的微服务,它能够非常简单地订阅来自于某个渠道的事件消息,并对接收到的消息进行处理,于此同时,它还能够向该渠道发送事件消息,以便