上一篇介绍了在不整合Consul的情况下,如何使用identity server。在实际应用环境中,内部服务一般是不对外暴露的,所以现在我们把consul考虑进来,稍作修改就可以了。
环境介绍,我们有一个OrderService和PartnerService,其中的/api/default是受权限保护的,还有一个ocelot网关和identity server4的权限服务。
可以参照之前的文章先把权限服务集成到consul。
大致流程是:首先在网关注册认证服务,修改认证服务资源,在api服务中集成认证
API网关注册认证服务
修改Startup
// IdentityServer
#region IdentityServerAuthenticationOptions => need to refactor
Action<IdentityServerAuthenticationOptions> isaOptClient = option =>
{
option.Authority = Configuration["IdentityService:Uri"];
option.ApiName = "serviceorder";
option.RequireHttpsMetadata = Convert.ToBoolean(Configuration["IdentityService:UseHttps"]);
option.SupportedTokens = SupportedTokens.Both;
option.ApiSecret = Configuration["IdentityService:ApiSecrets:orderservice"];
};
Action<IdentityServerAuthenticationOptions> isaOptProduct = option =>
{
option.Authority = Configuration["IdentityService:Uri"];
option.ApiName = "servicepartner";
option.RequireHttpsMetadata = Convert.ToBoolean(Configuration["IdentityService:UseHttps"]);
option.SupportedTokens = SupportedTokens.Both;
option.ApiSecret = Configuration["IdentityService:ApiSecrets:partnerservice"];
};
#endregion
services.AddAuthentication()
.AddIdentityServerAuthentication("PartnerServiceKey", isaOptProduct)
.AddIdentityServerAuthentication("OrderServiceKey", isaOptClient);
配置文件如下
{
"Swagger": {
"DocName": "ZJ.ApiGateway",
"Version": "v1",
"Title": "API Gateway Service",
"ServiceDocNames": "serviceorder,servicepartner,serviceauthorize" // Swagger doc name list
},
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"IdentityService": {
"Uri": "http://192.168.8.157:5100",
"UseHttps": false,
"ApiSecrets": {
"orderservice": "ordersecret",
"partnerservice": "partnersecret"
}
},
"AllowedHosts": "*"
}
修改ocelotsettings.json,给权限服务加上路由,如果需要swagger,也加上
// API:Service.Authorize
// --> swagger part
{
"DownstreamPathTemplate": "/doc/serviceauthorize-gateway/swagger.json",
"DownstreamScheme": "http",
"ServiceName": "Service.Authorize",
"LoadBalancer": "RoundRobin",
"UseServiceDiscovery": true,
"UpstreamPathTemplate": "/doc/serviceauthorize/swagger.json",
"UpstreamHttpMethod": [ "GET", "POST", "DELETE", "PUT" ]
},
{
"UseServiceDiscovery": true, // use Consul service discovery
"DownstreamPathTemplate": "/{url}",
"DownstreamScheme": "http",
"ServiceName": "Service.Authorize",
"LoadBalancerOptions": {
"Type": "RoundRobin"
},
"UpstreamPathTemplate": "/api/Serviceauthorize/{url}",
"UpstreamHttpMethod": [ "Get", "Post" ],
"ReRoutesCaseSensitive": false, // non case sensitive
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 2, // 允许多少个异常请求
"DurationOfBreak": 5000, // 熔断的时间,单位为毫秒
"TimeoutValue": 3000 // 如果下游请求的处理时间超过多少则视如该请求超时
}
}
修改权限服务
修改IdentityServerConfig类
public static class IdentityServerConfig
{
/// <summary>
/// 允许使用认证服务的api列表
/// </summary>
/// <returns></returns>
public static IEnumerable<ApiResource> GetApiResources()
{
return new List<ApiResource>
{
new ApiResource("serviceorder", "Default (all) API"),
new ApiResource("servicepartner", "Default (all) API1"),
};
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public static IEnumerable<IdentityResource> GetIdentityResources()
{
return new List<IdentityResource>
{
new IdentityResources.OpenId(),
new IdentityResources.Profile(),
new IdentityResources.Email(),
new IdentityResources.Phone()
};
}
/// <summary>
/// 允许使用认证服务的应用客户端
/// </summary>
/// <returns></returns>
public static IEnumerable<Client> GetClients(IConfiguration Configuration)
{
return new List<Client>
{
new Client
{
ClientId = "default_web_client",
ClientName="default_name",
AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
AllowedScopes =
{
"serviceorder",
"servicepartner",
},
ClientSecrets = new[]{ new Secret("secret1".Sha256())}
},
new Client
{
ClientId = "default_app_client",
ClientName="default_name11",
AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
AllowedScopes =
{
"serviceorder",
},
ClientSecrets = new[]{ new Secret("secret2".Sha256())}
},
new Client
{
ClientId = "default_mvc_client",
ClientName="default_name111",
AllowedGrantTypes = GrantTypes.Implicit,
RedirectUris = { Configuration["Clients:MvcClient:RedirectUri"] },
AllowedScopes =
{
"serviceorder",
},
ClientSecrets = new[]{ new Secret("secret3".Sha256())}
}
};
}
}
注意这里的Clients,这么设定的目的是当使用default_web_client时可以访问servicePartner以及serviceOrder,当使用default_app_client时只能访问serviceorder
修改api服务
修改ConfigureServices
// identity server
services.AddMvcCore().AddAuthorization().AddJsonFormatters();
services.AddAuthentication(_appConfiguration["IdentityService:DefaultScheme"]).AddIdentityServerAuthentication(_appConfiguration["IdentityService:DefaultScheme"], options =>
{
options.Authority = _appConfiguration["IdentityService:Uri"];
options.RequireHttpsMetadata = false;
options.ApiName = "serviceorder"; // match with configuration in IdentityServer
});
配置文件如下,注意defaultScheme必须和网关中配置的AddIdentityServerAuthentication一致
"IdentityService": {
"Uri": "http://192.168.8.157:5100",
"DefaultScheme": "OrderServiceKey",
"UseHttps": false,
"ApiSecret": "clientsecret"
}
发布到iis开始测试,我的测试环境中order服务端口是5000,partner服务端口是5001,认证服务端口5100,api网关端口5555
首先请求token,地址填写api网关地址,client_id、client_secret和权限服务中设置的一致,其他按下图填写
成功请求到token,按照我们在权限服务中的配置,这个token是属于default_web_client的,那么它可以用在serviceorder和servicepartner这两个api中
请求serviceorder,可以正常获得结果,注意在Auth选项卡中选择Bearer Token并填写刚才取得的access_token
请求servicepartner,也可以正常返回结果
现在我们换一个clientId,换成default_app_client,理论上它只能请求serviceorder,而不能请求servicepartner
可以看到请求servicepartner时返回了401 Unauthorized,测试通过。
隐藏client_secret
上述方式有一个较大的问题,那就是client_id对应的client_secret会暴露在客户端的请求体中。既然验证请求要经过api网关,那可以考虑在api网关做一次人工转发,在请求体中加上这个client_secret,具体可以看参考文章,此处不再展开。
总结
到这一步,微服务架构已经基本成型,consul作为服务中心统筹管理所有的api服务,独立的权限服务通过consul提供权限验证、用户注册、注销等功能。下一步需要重构代码,重新梳理项目结构,整理完成后接入CAP就基本可以开始开发。