在前面五篇博文后,我们已经实现了通过User.Identity来调用User.Api实现认证获取到token,所以我们应该将User.Api除了认证接口外的接口都添加到Api.Gateway网关中,同时也将User.Identity添加到网关中,实现外网访问统一入口。
Ocelot很好的支持了IdentityServer4,所以在Api.Gateway中需要添加IdentityServer4和IdentityServer4.AccessTokenValidation两个Nuget包
Install-Package IdentityServer4
Install-Package IdentityServer4.AccessTokenValidation
在Ocelot.json中添加User.Api和User.Identity的路由配置
{ "ReRoutes": [ { "DownstreamPathTemplate": "/api/user", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 63679 } ], "UpstreamPathTemplate": "/user", "UpstreamHttpMethod": [ "Get", "Patch" ], "AuthenticationOptions": { "AuthenticationProviderKey": "Finbook", "AllowedScopes": [ "user_api" ] } }, { "DownstreamPathTemplate": "/api/user/baseinfo/{userId}", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 63679 } ], "UpstreamPathTemplate": "/user/baseinfo/{userId}", "UpstreamHttpMethod": [ "Get" ], "AuthenticationOptions": { "AuthenticationProviderKey": "Finbook", "AllowedScopes": [ "user_api" ] } }, { "DownstreamPathTemplate": "/api/user/tags", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 63679 } ], "UpstreamPathTemplate": "/user/tags", "UpstreamHttpMethod": [ "Get", "Put" ], "AuthenticationOptions": { "AuthenticationProviderKey": "Finbook", "AllowedScopes": [ "user_api" ] } }, { "DownstreamPathTemplate": "/api/user/search", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 63679 } ], "UpstreamPathTemplate": "/user/search", "UpstreamHttpMethod": [ "Post" ], "AuthenticationOptions": { "AuthenticationProviderKey": "Finbook", "AllowedScopes": [ "user_api" ] } }, { "DownstreamPathTemplate": "/connect/{catchAll}", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 56424 } ], "UpstreamPathTemplate": "/connect/{catchAll}", "UpstreamHttpMethod": [ "Post" ] }, { "DownstreamPathTemplate": "/.well-known/{catchAll}", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 56424 } ], "UpstreamPathTemplate": "/.well-known/{catchAll}", "UpstreamHttpMethod": [ "Get" ] } ], "GlobalConfiguration": { "BaseUrl": "http://localhost" } }
可以看到User.Api的路由都添加了 AuthenticationOptions 选项来授权,添加完配置后需要在Startup中注入IdentityServer
var authenticationProviderKey = "Finbook"; services.AddAuthentication() .AddIdentityServerAuthentication(authenticationProviderKey, options=> { options.Authority = "http://localhost:56424"; //User.Identity服务器的Url options.ApiName = "gateway_api"; options.SupportedTokens = SupportedTokens.Both; options.ApiSecret = "secret"; options.RequireHttpsMetadata = false; });
启动项目,通过postman可以测试拿到token
如果未携带token访问想要获取用户信息将返回401
将User.Api添加到网关后,如果我们需要获取当前用户信息该怎么办呢,这时候已经不像以前单体架构可以使用session来保存当前用户信息了,我们需要使用Asp.Net Core Identity 。
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.RequireHttpsMetadata = false; options.Audience = "user_api"; options.Authority = "http://localhost"; // Api.Gateway网关Url });
app.UseAuthentication();
可以在BaseController中获取到当前用户信息
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using User.API.Dtos; namespace User.API.Controllers { public class BaseController : Controller { protected UserIdentity UserIdentity { get { return new UserIdentity { UserId = Convert.ToInt32(User.Claims.FirstOrDefault(c => c.Type == "sub").Value), Name = User.Claims.FirstOrDefault(c => c.Type == "name").Value, Company = User.Claims.FirstOrDefault(c=>c.Type == "company").Value, Title = User.Claims.FirstOrDefault(c=>c.Type == "title").Value, Avatar = User.Claims.FirstOrDefault(c=>c.Type == "avatar").Value }; } } } }