根据 scope 策略设置受保护api资源 访问权限

1 添加 apiscope

2 添加 apiresource

添加api名为“client_credentials_apis”的apiresource,并把作用域“client_credentials_apis.IdentityUserController.scope”和“client_credentials_apis.WeatherForecastController.scope”添加到该apiresource中

 

 

3 在 ids 添加客户端

添加客户端,添加客户端密钥,设置授权类型(比如 客户端凭证方式),并至少设置一个 自定义的 apiscope(如添加 client_credentials_apis.WeatherForecastController.scope);token类型默认为 jwt。

4 客户端获取 token并使用 该token访问api资源

 

 接下来给客户端添加  client_credentials_apis.IdentityUserController.scope ,重新访问结果如下:

 

 再给客户端添加 client_credentials_apis.WeatherForecastController.scope,重新访问结果如下

客户端添加作用域如下图:

 

 

 5 相关代码

5.1 api资源端代码如下:

配置如下:

namespace Resources_Https
{
    public class Config
    {
        /// <summary>
        /// identity server 地址
        /// </summary>
        public const string IdentityServerUri = "https://localhost:44310";

        /// <summary>
        /// reference tokens 的 clientId
        /// </summary>
        public const string ApiName = "client_credentials_apis";

        /// <summary>
        /// reference tokens 的 clientSecret
        /// </summary>
        public const string ApiSecret = "123456";
    }
}

startup.cs 代码如下:

using IdentityModel.AspNetCore.OAuth2Introspection;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.OpenApi.Models;

namespace Resources_Https
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            // nuget 安装 Microsoft.AspNetCore.Authentication.JwtBearer
            // jwt tokens
            services.AddAuthentication(OAuth2IntrospectionDefaults.AuthenticationScheme)
            .AddJwtBearer("Bearer", options =>
            {
                options.Authority = Config.IdentityServerUri;

                // 设置 https
                options.RequireHttpsMetadata = true;

                options.Audience = Config.ApiName;

                // 支持 jwt 和 reference 两种 token 
                // if token does not contain a dot, it is a reference token
                options.ForwardDefaultSelector = context => "Introspection";
            });

            // reference tokens
            services.AddAuthentication("Introspection")
            .AddOAuth2Introspection("Introspection", options =>
            {
                options.Authority = Config.IdentityServerUri;

                // this maps to the API resource name and secret
                options.ClientId = Config.ApiName; // api 名
                options.ClientSecret = Config.ApiSecret; // 配置的 api 秘钥
            });

            // 策略授权
            services.AddAuthorization(options =>
            {
                // client allowedscope 包含 client_credentials_apis.WeatherForecastController.scope 才能访问
                options.AddPolicy("WeatherForecastController",
                    policy => policy.RequireScope("client_credentials_apis.WeatherForecastController.scope")
                    );

                options.AddPolicy("IdentityUserController",
                    policy => policy.RequireScope("client_credentials_apis.IdentityUserController.scope")
                    );
            });

            services.AddControllers();

            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "Resources_Https", Version = "v1" });
            });
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseSwagger();
                app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Resources_Https v1"));
            }

            app.UseHttpsRedirection();

            app.UseRouting();

            app.UseAuthentication();
            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
}

 

TestController代码:

    [ApiController]
    [Route("[controller]/[action]")]
    [Authorize]
    public class TestController : ControllerBase
    {
        public IActionResult Ping()
        {
            return new JsonResult(new { code = 0, msg = "TestController pong" });
        }
    }

IdentityUserController 代码:

    [ApiController]
    [Route("[controller]/[action]")]
    [Authorize(Policy = "IdentityUserController")]
    public class IdentityUserController : ControllerBase
    {
        [HttpGet]
        public IActionResult Ping()
        {
            return new JsonResult(new { code = 0, msg = "IdentityUserController pong" });
        }

        [HttpGet]
        public IActionResult GetClaims()
        {
            var claims = User.Claims.ToList();

            var id = User.Identity as ClaimsIdentity;
            var claim = id.FindFirst(JwtClaimTypes.Subject);


            return new JsonResult(claims);
        }
    }

WeatherForecastController 代码:

    [ApiController]
    [Route("[controller]/[action]")]
    [Authorize(Policy = "WeatherForecastController")]
    public class WeatherForecastController : ControllerBase
    {
        [HttpGet]
        public IActionResult Ping()
        {
            return new JsonResult(new { code = 0, msg = "WeatherForecastController pong" });
        }
    }

5.2 客户端代码

配置代码:

    public class Config
    {
        /// <summary>
        /// identity server 地址
        /// </summary>
        public const string IdentityServerUri = "https://localhost:44310";

        /// <summary>
        /// 受保护的api地址
        /// </summary>
        public const string ResourceUri = "https://localhost:6001";

        public const string ClientId = "ClientCredentials_1_ClientId";

        public const string ClientSecret = "511536EF-F270-4058-80CA-1C89C192F69A";

        public const string GrantType = "client_credentials";
    }

获取token和访问资源代码:

    /// <summary>
    /// 使用 HttpClient 通过客户端凭证方式获取token与资源
    /// 适用场景:一般用于服务端应用与服务端应用交互
    /// 请求token链接格式:{idsServer}/connect/token?client_id={}&client_secret={}&grant_type=client_credentials
    /// </summary>
    public class HttpClient_ClientCredentials
    {
        public static void Run()
        {
            // 先获取 access token
            var token_res = string.Empty;
            string postData = $"client_id={Config.ClientId}&client_secret={Config.ClientSecret}&grant_type={Config.GrantType}";
            using (var httpClient = new HttpClient())
            {
                using (HttpContent httpContent = new StreamContent(new MemoryStream(Encoding.UTF8.GetBytes(postData))))
                {
                    httpContent.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
                    token_res = httpClient.PostAsync($"{Config.IdentityServerUri}/connect/token", httpContent).Result.Content.ReadAsStringAsync().Result;
                }
            }

            // 使用 token 访问资源
            if (!string.IsNullOrEmpty(token_res)){
                using(HttpClient getClient = new HttpClient())
                {
                    getClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + JObject.Parse(token_res)["access_token"].ToString());
                    // 有token就能访问
                    var apiRes1 = getClient.GetStringAsync($"{Config.ResourceUri}/Test/Ping").Result;
                    // 有token就能访问且 client allowedscope 包含 client_credentials_apis.IdentityUserController.scope 才能访问
                    var apiRes2 = getClient.GetStringAsync($"{Config.ResourceUri}/IdentityUser/Ping").Result;
                    // 有token就能访问且 client allowedscope 包含 client_credentials_apis.WeatherForecastController.scope 才能访问
                    var res_res3 = getClient.GetStringAsync($"{Config.ResourceUri}/WeatherForecast/Ping").Result;
                }
            }
        }
    }

 

参考资源

https://blog.csdn.net/ma_jiang/article/details/107120049

posted @ 2022-01-22 18:16  温故纳新  阅读(842)  评论(1编辑  收藏  举报