威势网络,为您的企业和团队注入互联网活力!
服务热线:138-9741-0341

[原创] IdentityServer4权限控制---客户端创建、获取TOKEN及访问API资源(三)

发布日期:2022/9/3 作者: 浏览:1152

    经过前面两节课,我们已经完成了API服务器的搭建与IDS4身份验证服务器的搭建,如果还没有看的朋友请到这里围观:


[原创] IdentityServer4权限控制---客户端授权模式之API服务器搭建(一)

[原创] IdentityServer4权限控制---客户端授权模式之IDS4认证服务器搭建(二)


    API服务器是我们要保护的资源服务器,我们希望只授权给通过身份验证的客户端去访问,而身份验证的工作是由我们搭建的IDS4服务器来完成的。现在我们模拟一个场景,我们已经将上面两台服务器成功部署到公司的服务器上去了,现在有个第三方用户,他开发了一头桌面应用,叫做client.exe,该应用在成功运行以后要读取我们的资源服务器上的接口数据,也就是访问 https://localhost:6001/上面的三个接口数据,我们希望只对身份已经证的用户开放,并不是随便人写几行代码就把我们的数据给偷走了,这里CLIENT.EXE就是我们的客户端,为此我简单画了一张图,如下:

(注意:步骤4、5、5'是假想的,我们要通过实验去验证它是否存在)

    客户端程序为了访问API资源服务器上的接口数据,先要进行身份验证才可以,不然会被资源服务器拒绝,所以,它要先去IDS4服务器申请TOKEN,申请TOKEN需要携带必要的身份信息,上图左下角橘色框中便是。成功拿到TOKEN以后,客户端再发起一个网络连接,去申请API资源,这个过程中要向API资源服务器提交身份认证用的TOKEN,右下角绿色便是。为了流程理解方便,我在上面标注了数据代表步骤顺序。资源服务器得到TOKEN以后,是JWT格式的,直接在本机验证,(这里要特别注意一下!!!,也就是说:步骤3以后直接返回,而不是通过步骤45后再返回

    现在我们需要去打造一个客户端client.exe去申请我们的TOKEN以及访问我们的资源。

创建一个控制台程序

选择新建目录

选择.NET6.0下一步,就建好了。我们的直接用官网提供的代码去测试,如下,


// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.

using IdentityModel.Client;
using Newtonsoft.Json.Linq;
using System;
using System.Net.Http;
using System.Threading.Tasks;

namespace Client
{
    public class Program
    {
        private static async Task Main()
        {
            // discover endpoints from metadata
            var client = new HttpClient();

            var disco = await client.GetDiscoveryDocumentAsync("https://localhost:5001"); //取得证书 https://localhost:5001/.well-known/openid-configuration
            if (disco.IsError)
            {
                Console.WriteLine(disco.Error);
                return;
            }

            // 请求token令牌
            var tokenResponse = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest
            {
                Address = disco.TokenEndpoint,
                ClientId = "client",
                ClientSecret = "secret",
                Scope = "api1"
                //Scope = "identity"
            });

            if (tokenResponse.IsError)
            {
                Console.WriteLine(tokenResponse.Error);
                return;
            }

            Console.WriteLine(tokenResponse.Json);//输出令牌信息
            Console.WriteLine("\n\n");

            // call api 访问我们的API资源,注意,每个资源的权限要求是不一样的
            var apiClient = new HttpClient();
            apiClient.SetBearerToken(tokenResponse.AccessToken);

            var response = await apiClient.GetAsync("https://localhost:6001/identity"); //该资源要求登录用户才可以访问
            if (!response.IsSuccessStatusCode)
            {
                Console.WriteLine(response.StatusCode);
            }
            else
            {
                var content = await response.Content.ReadAsStringAsync();
                Console.WriteLine(JArray.Parse(content));
            }

            response = await apiClient.GetAsync("https://localhost:6001/api/Students");  //该资源匿名可访问
            if (!response.IsSuccessStatusCode)
            {
                Console.WriteLine(response.StatusCode);
            }
            else
            {
                var content = await response.Content.ReadAsStringAsync();
                Console.WriteLine(JArray.Parse(content));
            }
        }
    }
}
我们把IdentityModel包引起去,再把Newtonsoft.Json也引进去,在第二课中讲到,Identity  接口是要验证用户才可以访问成功的,未登录用户返回401。现在我们运行client.exe试试,运行之前先运行我们的API服务器与身份验证服务器,再运行client.exe,看到CMD窗口返回以下信息:


{"access_token":"eyJhbGciOiJSUzI1NiIsImtpZCI6IkU1OEMxMkExMUU3NTkwRTk3NEY3REREQTA3NEIwRTUwIiwidHlwIjoiYXQrand0In0.eyJuYmYiOjE2NjIxOTcyMzMsImV4cCI6MTY2MjIwMDgzMywiaXNzIjoiaHR0cHM6Ly9sb2NhbGhvc3Q6NTAwMSIsImNsaWVudF9pZCI6ImNsaWVudCIsImp0aSI6IjU3RDA4MkIxN0NFRjUxM0M4MzVFRENFNzkxQ0NGRDJGIiwiaWF0IjoxNjYyMTk3MjMzLCJzY29wZSI6WyJhcGkxIl19.pYY8nTQvHQMeKjn5LkE-OO2xzsnS4xyicusJ88SMyThqelFq95fhqZC3jUoOFqDUy8ex7S1Q_c8RL0G3dnvuIIiyg6ECPxRBNHwVfztdzVpoe7qOEyYdP_Z9lqwcgJdbWiWCGzcPkWzErikFIHDe2KwprD1_YlDBN67ze96sVWypNrSBWhFgPf80B3wfDSE3z1apoz0Pe8QqkoWpE9xT-Y0_vz5s3m-CaNl6ar8M1Wk2LdvDYwk3UgJ5p4XViwtookPUj48rKVseohe7qQtTpXpT0RXf0JLuXmAhxRMweXBZMNY64F-d9MbqftyBKlDffXTgoK8JeaujcYdZ9nLy6A","expires_in":3600,"token_type":"Bearer","scope":"api1"}



[
  {
    "type": "nbf",
    "value": "1662197233"
  },
  {
    "type": "exp",
    "value": "1662200833"
  },
  {
    "type": "iss",
    "value": "https://localhost:5001"
  },
  {
    "type": "client_id",
    "value": "client"
  },
  {
    "type": "jti",
    "value": "57D082B17CEF513C835EDCE791CCFD2F"
  },
  {
    "type": "iat",
    "value": "1662197233"
  },
  {
    "type": "scope",
    "value": "api1"
  }
]
[
  {
    "boinYear": 1986,
    "xingMing": "QiQi",
    "age": 36,
    "address": "中国"
  },
  {
    "boinYear": 1970,
    "xingMing": "Black Smith",
    "age": 52,
    "address": "英国"
  },
  {
    "boinYear": 1957,
    "xingMing": "John",
    "age": 65,
    "address": "日本"
  },
  {
    "boinYear": 1975,
    "xingMing": "John",
    "age": 47,
    "address": "加拿大"
  },
  {
    "boinYear": 1975,
    "xingMing": "QiQi",
    "age": 47,
    "address": "美国"
  }
]


LOOK,我们成功获取到了Identity接口的数据!我们接着文章开始处留下的问题分别做这样的实验:

一、在 client.exe从identityserver4获得tokenResponse.AccessToken后,将identityserver4服务器关闭,分别访问两个API接口。

二、在获得tokenResponse.AccessToken后,将它保存下来,然后关闭identityserver4服务器,也就是说,用上次获得到TOKEN,在验证服务器关闭的状态下去访问API资源。

通过上面的实验,我们知道,在identityserver4关闭的时候,我们的身份验证照常可以通过,也就是说,登录获得TOKEN是在Identityserver4上进行的,而获得TOKEN以后就没它什么事了。文章开始处的流程图中4、5、5‘ 步骤是不存在的。

这样,我们的客户端就只有通过了身份验证才可以访问到我们的资源,也就是说资源得到了保护。但是很多小伙伴要问了,你这也太粗暴了吧!我怎么样对API的资源进行更精细化的保护呢? 别着急,我们打开APITEST项目,在program.cs 中写一个权限策略来实现更精细化的控制。


builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("ApiScope", policy =>
    {
        policy.RequireAuthenticatedUser();
        policy.RequireClaim("scope", "api1");
    });
});
就这样,我们在program.cs启动之时注册了一个安全策略,我们只需要在需要验证的地放这样去引用就可以了



    //[Authorize]
    [Authorize(Policy = "ApiScope")]
这样就不是所有登录的用户都可以访问我们的资源了,而是需要满足ApiScope策略的用户才可以!根据这个原理,我们可以扩展很多。IDS4官方宣称,给资源一个别名是比较推荐的一种做法,给了别名,其实就可以用不同的别名来授权。尝试将API服务器换成域名,和IDS4分别不同的域名,让客户端跨域申请TOKEN及授权,任然是可以的,看来还是比较方便的,其它功能等后面研究再深入一些,我再回来补充。。。

今天的源码下载

看文章一天,写文章一天,写作不易,朋友们留言支持一下就不胜感激了。。。

原创文章,创作不易,转载请注明出处:https://www.qhwins.com/article-29


下拉加载更多评论
最新评论
暂无!