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

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

"applicationUrl": "http://localhost:9080"
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

二、Ocelot集成ids4

2.1 Ocelot保护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();
}

 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

修改 ocelot.json 配置文件:

{
  "DownstreamPathTemplate": "/products",
  "DownstreamScheme": "http",
  "UpstreamPathTemplate": "/products",
  "UpstreamHttpMethod": [ "Get" ],
  "ServiceName": "ProductService",
  ......
  "AuthenticationOptions": {
    "AuthenticationProviderKey": "productService",
    "AllowScopes": []
  }
},
{
  "DownstreamPathTemplate": "/orders",
  "DownstreamScheme": "http",
  "UpstreamPathTemplate": "/orders",
  "UpstreamHttpMethod": [ "Get" ],
  "ServiceName": "OrderService",
  ......
  "AuthenticationOptions": {
    "AuthenticationProviderKey": "orderService",
    "AllowScopes": []
  }
}

 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

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

2.2 Ocelot代理ids4

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

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

 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

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

让网关服务运行在9070端口,/Properties/launchSettings.json 修改一下:

"applicationUrl": "http://localhost:9070"
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

三、客户端集成

首先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
    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();
}

 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

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

/// 
/// 获取产品数据
/// 
/// 
/// 
Task<string> GetProduct(string accessToken);

/// 
/// 获取订单数据
/// 
/// 
/// 
Task<string> GetOrder(string accessToken);

 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

修改 /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", 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;
}

 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

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

[Authorize]
public class HomeController : Controller
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

修改 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();
}

 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

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

四、测试

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

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

在这里插入图片描述

Ctor+F5启动项目。

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

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

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

在这里插入图片描述
清除 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


在这里插入图片描述

注:本文转载自blog.csdn.net的Microi风闲的文章"https://lisaisai.blog.csdn.net/article/details/145290197"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接

评论记录:

未查询到任何数据!