.Net Core微服务入门全纪录(七)——IdentityServer4-授权认证

.Net Core微服务入门全纪录(七)——IdentityServer4-授权认证,第1张

概述Tips:本篇已加入系列文章阅读目录,可点击查看更多相关文章。 前言 上一篇【.Net Core微服入门全纪录(六)——EventBus-事件总线】中使用CAP完成了一个简单的Eventbus,实现

Tips:本篇已加入系列文章阅读目录,可点击查看更多相关文章。

前言

上一篇【.Net Core微服务入门全纪录(六)——EventBus-事件总线】中使用CAP完成了一个简单的Eventbus,实现了服务之间的解耦和异步调用,并且做到数据的最终一致性。这一篇将使用IDentityServer4来搭建一个鉴权中心,来完成授权认证相关的功能。

IDentityServer4官方文档:https://identityserver4.readthedocs.io/

鉴权中心创建IDs4项目

关于IDentityServer4的基本介绍和模板安装可以看一下我的另一篇博客【IdentityServer4 4.x版本 配置Scope的正确姿势】,下面直接从创建项目开始。

来到我的项目目录下执行:dotnet new is4inmem --name IDS4.AuthCenter

执行完成后会生成以下文件:

用vs2019打开之前的解决方案,把刚刚创建的IDs项目添加进来:

将此项目设为启动项,先运行看一下效果:

项目正常运行,下面需要结合我们的业务稍微修改一下默认代码。

鉴权中心配置

修改Startup的ConfigureServices方法:

// in-memory,code configbuilder.AddInMemoryIDentityResources(Config.IDentityResources);builder.AddInMemoryAPIScopes(Config.APIScopes);builder.AddInMemoryAPIResources(Config.APIResources);builder.AddInMemoryClIEnts(Config.ClIEnts);

Config类:

public static class Config{    public static IEnumerable<IDentityResource> IDentityResources =>        new IDentityResource[]        {            new IDentityResources.OpenID(),new IDentityResources.Profile(),};    public static IEnumerable<APIResource> APIResources =>        new APIResource[]        {            new APIResource("orderAPI","订单服务")            {                APISecrets ={ new Secret("orderAPI secret".Sha256()) },Scopes = { "orderAPIScope" }            },new APIResource("productAPI","产品服务")            {                APISecrets ={ new Secret("productAPI secret".Sha256()) },Scopes = { "productAPIScope" }            }        };    public static IEnumerable<APIScope> APIScopes =>        new APIScope[]        {            new APIScope("orderAPIScope"),new APIScope("productAPIScope"),};    public static IEnumerable<ClIEnt> ClIEnts =>        new ClIEnt[]        {            new ClIEnt            {                ClIEntID = "web clIEnt",ClIEntname = "Web ClIEnt",AllowedGrantTypes = GrantTypes.Code,ClIEntSecrets = { new Secret("web clIEnt secret".Sha256()) },RedirectUris = { "http://localhost:5000/signin-oIDc" },FrontChannellogoutUri = "http://localhost:5000/signout-oIDc",PostlogoutRedirectUris = { "http://localhost:5000/signout-callback-oIDc" },AllowedScopes = new [] {                    IDentityServerConstants.StandardScopes.OpenID,IDentityServerConstants.StandardScopes.Profile,"orderAPIScope","productAPIScope"                },AllowAccesstokensViabrowser = true,RequireConsent = true,//是否显示同意界面                AllowRememberConsent = false,//是否记住同意选项            }        };}

Config中定义了2个API资源:orderAPI,productAPI。2个Scope:orderAPIScope,productAPIScope。1个客户端:web clIEnt,使用Code授权码模式,拥有openID,profile,orderAPIScope,productAPIScope 4个scope。

TestUsers类:

public class TestUsers{    public static List<TestUser> Users    {        get        {            var address = new            {                street_address = "One Hacker Way",locality = "HeIDelberg",postal_code = 69118,country = "Germany"            };                        return new List<TestUser>            {                new TestUser                {                    SubjectID = "818727",Username = "alice",Password = "alice",Claims =                    {                        new Claim(JwtClaimTypes.name,"Alice Smith"),new Claim(JwtClaimTypes.Givenname,"Alice"),new Claim(JwtClaimTypes.Familyname,"Smith"),new Claim(JwtClaimTypes.Email,"AliceSmith@email.com"),new Claim(JwtClaimTypes.EmailVerifIEd,"true",ClaimValueTypes.Boolean),new Claim(JwtClaimTypes.WebSite,"http://alice.com"),new Claim(JwtClaimTypes.Address,JsonSerializer.Serialize(address),IDentityServerConstants.ClaimValueTypes.Json)                    }                },new TestUser                {                    SubjectID = "88421113",Username = "bob",Password = "bob","Bob Smith"),"Bob"),"BobSmith@email.com"),"http://bob.com"),IDentityServerConstants.ClaimValueTypes.Json)                    }                }            };        }    }}

TestUsers没有做修改,用项目模板默认生成的就行。这里定义了2个用户alice,bob,密码与用户名相同。

至此,鉴权中心的代码修改就差不多了。这个项目也不放docker了,直接用vs来启动,让他运行在9080端口。/PropertIEs/launchSettings.Json修改一下:"applicationUrl": "http://localhost:9080"

Ocelot集成IDs4Ocelot保护API资源

鉴权中心搭建完成,下面整合到之前的Ocelot.APIGateway网关项目中。

首先NuGet安装IDentityServer4.AccesstokenValIDation

修改Startup:

public voID ConfigureServices(IServiceCollection services){    services.AddAuthentication(IDentityServerAuthenticationDefaults.AuthenticationScheme)        .AddIDentityServerAuthentication("orderService",options =>        {            options.Authority = "http://localhost:9080";//鉴权中心地址            options.APIname = "orderAPI";            options.SupportedTokens = SupportedTokens.Both;            options.APISecret = "orderAPI secret";            options.RequirehttpsMetadata = false;        })        .AddIDentityServerAuthentication("productService",options =>        {            options.Authority = "http://localhost:9080";//鉴权中心地址            options.APIname = "productAPI";            options.SupportedTokens = SupportedTokens.Both;            options.APISecret = "productAPI secret";            options.RequirehttpsMetadata = false;        });    //添加ocelot服务    services.AddOcelot()        //添加consul支持        .AddConsul()        //添加缓存        .AddCacheManager(x =>        {            x.WithDictionaryHandle();        })        //添加Polly        .AddPolly();}

修改ocelot.Json配置文件:

{  "DownstreamPathTemplate": "/products","DownstreamScheme": "http","UpstreamPathTemplate": "/products","UpstreamhttpMethod": [ "Get" ],"Servicename": "ProductService",......  "Authenticationoptions": {    "AuthenticationProvIDerKey": "productService","AllowScopes": []  }},{  "DownstreamPathTemplate": "/orders","UpstreamPathTemplate": "/orders","Servicename": "OrderService",......  "Authenticationoptions": {    "AuthenticationProvIDerKey": "orderService","AllowScopes": []  }}

添加了Authenticationoptions节点,AuthenticationProvIDerKey对应的是上面Startup中的定义。

Ocelot代理IDs4

既然网关是客户端访问API的统一入口,那么同样可以作为鉴权中心的入口。使用Ocelot来做代理,这样客户端也无需知道鉴权中心的地址,同样修改ocelot.Json:

{  "DownstreamPathTemplate": "/{url}","DownstreamHostAndPorts": [    {      "Host": "localhost","Port": 9080    }  ],"UpstreamPathTemplate": "/auth/{url}","UpstreamhttpMethod": [    "Get","Post"  ],"LoadBalancerOptions": {    "Type": "RoundRobin"  }}

添加一个鉴权中心的路由,实际中鉴权中心也可以部署多个实例,也可以集成Consul服务发现,实现方式跟前面章节讲的差不多,这里就不再赘述。

让网关服务运行在9070端口,/PropertIEs/launchSettings.Json修改一下:"applicationUrl": "http://localhost:9070"

客户端集成

首先NuGet安装Microsoft.AspNetCore.Authentication.OpenIDConnect

修改Startup:

public voID ConfigureServices(IServiceCollection services){    services.AddAuthentication(options =>        {            options.DefaultScheme = "cookies";            options.DefaultChallengeScheme = "oIDc";        })        .Addcookie("cookies")        .AddOpenIDConnect("oIDc",options =>        {            options.Authority = "http://localhost:9070/auth";//通过网关访问鉴权中心            //options.Authority = "http://localhost:9080";            options.ClIEntID = "web clIEnt";            options.ClIEntSecret = "web clIEnt secret";            options.ResponseType = "code";            options.RequirehttpsMetadata = false;            options.Savetokens = true;            options.Scope.Add("orderAPIScope");            options.Scope.Add("productAPIScope");        });    services.AddControllersWithVIEws();        //注入IServiceHelper    //services.AddSingleton<IServiceHelper,ServiceHelper>();        //注入IServiceHelper    services.AddSingleton<IServiceHelper,GatewayServiceHelper>();}// This method gets called by the runtime. Use this method to configure the http request pipeline.public voID Configure(IApplicationBuilder app,IWebHostEnvironment env,IServiceHelper serviceHelper){    if (env.IsDevelopment())    {        app.UseDeveloperExceptionPage();    }    else    {        app.UseExceptionHandler("/Home/Error");    }    app.UseStaticfiles();    app.UseRouting();    app.UseAuthentication();    app.UseAuthorization();    app.UseEndpoints(endpoints =>    {        endpoints.MapControllerRoute(            name: "default",pattern: "{controller=Home}/{action=Index}/{ID?}");    });    //程序启动时 获取服务列表    //serviceHelper.GetServices();}

修改/Helper/IServiceHelper,方法定义增加accesstoken参数:

/// <summary>/// 获取产品数据/// </summary>/// <param name="accesstoken"></param>/// <returns></returns>Task<string> GetProduct(string accesstoken);/// <summary>/// 获取订单数据/// </summary>/// <param name="accesstoken"></param>/// <returns></returns>Task<string> Getorder(string accesstoken);

修改/Helper/GatewayServiceHelper,访问接口时增加Authorization参数,传入accesstoken:

public async Task<string> Getorder(string accesstoken){    var ClIEnt = new RestClIEnt("http://localhost:9070");    var request = new RestRequest("/orders",Method.GET);    request.Addheader("Authorization","Bearer " + accesstoken);    var response = await ClIEnt.ExecuteAsync(request);    if (response.StatusCode != httpStatusCode.OK)    {        return response.StatusCode + " " + response.Content;    }    return response.Content;}public async Task<string> GetProduct(string accesstoken){    var ClIEnt = new RestClIEnt("http://localhost:9070");    var request = new RestRequest("/products","Bearer " + accesstoken);    var response = await ClIEnt.ExecuteAsync(request);    if (response.StatusCode != httpStatusCode.OK)    {        return response.StatusCode + " " + response.Content;    }    return response.Content;}

最后是/Controllers/HomeController的修改。添加Authorize标记:

[Authorize]public class HomeController : Controller

修改Index action,获取accesstoken并传入:

public async Task<IActionResult> Index(){    var accesstoken = await httpContext.GetTokenAsync("access_token");    VIEwBag.OrderData = await _serviceHelper.Getorder(accesstoken);    VIEwBag.ProductData = await _serviceHelper.GetProduct(accesstoken);    return VIEw();}

至此,客户端集成也已完成。

测试

为了方便,鉴权中心、网关、web客户端这3个项目都使用vs来启动,他们的端口分别是9080,9070,5000。之前的OrderAPI和ProductAPI还是在docker中不变。

为了让vs能同时启动多个项目,需要设置一下,解决方案右键属性:

Ctor+F5启动项目。

3个项目都启动完成后,浏览器访问web客户端:http://localhost:5000/

因为我还没登录,所以请求直接被重定向到了鉴权中心的登录界面。使用alice/alice这个账户登录系统。

登录成功后,进入授权同意界面,你可以同意或者拒绝,还可以选择勾选scope权限。点击Yes,Allow按钮同意授权:

同意授权后,就能正常访问客户端界面了。下面测试一下部分授权,这里没做登出功能,只能手动清理一下浏览器cookie,IDs4登出功能也很简单,可以自行百度。

清除cookie后,刷新页面又会转到IDs4的登录界面,这次使用bob/bob登录:

这次只勾选orderAPIScope,点击Yes,Allow:

这次客户端就只能访问订单服务了。当然也可以在鉴权中心去限制客户端的API权限,也可以在网关层面ocelot.Json中限制,相信你已经知道该怎么做了。

总结

本文主要完成了IDentityServer4鉴权中心、Ocelot网关、web客户端之间的整合,实现了系统的统一授权认证。授权认证是几乎每个系统必备的功能,而IDentityServer4是.Net Core下优秀的授权认证方案。再次推荐一下B站@solenovex 杨老师的视频,地址:https://www.bilibili.com/video/BV16b411k7yM ,虽然视频有点老了,但还是非常受用。

需要代码的点这里:https://github.com/xiajingren/NetCoreMicroserviceDemo

总结

以上是内存溢出为你收集整理的.Net Core微服务入门全纪录(七)——IdentityServer4-授权认证全部内容,希望文章能够帮你解决.Net Core微服务入门全纪录(七)——IdentityServer4-授权认证所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1214768.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-05
下一篇 2022-06-05

发表评论

登录后才能评论

评论列表(0条)

保存