【IdentityServer4】分模块保护Api(4.x)

IdentityServer4(下文统称Ids4)官方已经从v3更新升级到了v4版本,最核心也最重要的一个更新,就是新增了ApiResourceScopes表,进一步细化了对资源服务器的限制粒度。之前我们是一个客户端只能针对一个资源服务器来操作,那该资源服务器下的所有api都会被保护,当然也都会被控制。所以是面向整个ApiResources的。
但是现在做了细化以后,一个资源服务器可以分隔出多个作用域Scope,那这样的话,我们就可以定义多个客户端,分模块的去访问同一个统一的资源服务器。如:client1只有权限读订单信息,没有写订单权限,可以将Order.WebApiAPI划分两个scope:Order.ReadOrder.Write,权限校验需要在资源服务器中自己去实现。

Ids4

1、Config

    public static class Config
    {
        public static IEnumerable<IdentityResource> IdentityResources=> new IdentityResource[]
            {
                new IdentityResources.OpenId()
            };

        // Defining an API Resource
        public static IEnumerable<ApiResource> Apis =>
            new List<ApiResource>{
            new ApiResource("Order.WebApi", "订单服务"){
                Scopes=new[]{ "Order.Read","Order.Write" }
            },
            new ApiResource("Product.WebApi", "产品服务")
            };
        //4.x新增ApiScope
        public static IEnumerable<ApiScope> GetApiScopes=>new[] { new ApiScope("Order.Read") , new ApiScope("Order.Write") };

        // Defining Client
        public static IEnumerable<Client> Clients =>
            new List<Client> {
            new Client
            {
                //没有交互式用户,使用clientid/secret进行身份验证  
                AllowedGrantTypes=GrantTypes.ClientCredentials,
                ClientId="client",
                ClientSecrets={new Secret("secret".Sha256())},
                //客户端可以访问的范围
                AllowedScopes={ "Order.Read", "Order.Write" }
            }
        };
    }

2、注册服务

builder.Services.AddIdentityServer()
.AddDeveloperSigningCredential()//在每次启动时,为令牌签名创建了一个临时密钥。在生成环境需要一个持久化的密钥。
.AddInMemoryIdentityResources(Config.IdentityResources)
.AddInMemoryApiScopes(Config.GetApiScopes)//4.x新增
.AddInMemoryApiResources(Config.Apis)
.AddInMemoryClients(Config.Clients);

资源服务器

1、添加认证服务

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        //.AddIdentityServerAuthentication()
        .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, option =>
        {
            option.Authority = "http://localhost:5000";
            option.RequireHttpsMetadata = false;
            option.Audience = "Order.WebApi";
        });

2、添加中间件

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

3、添加授权策略

builder.Services.AddAuthorization(options =>
{
    #region 订单权限策略
    //读权限
    options.AddPolicy("ReadOrder", builder =>
    {
        //客户端Scope中包含Order.Read才能访问
        builder.RequireClaim("scope", "Order.Read");
    });
    //写权限
    options.AddPolicy("WriteOrder", builder =>
    {
        //客户端Scope中包含Order.Write才能访问
        builder.RequireClaim("scope", "Order.Write");
    });
    #endregion

});

4、接口指定策略

    [ApiController]
    [Route("[controller]")]
    public class OrderController : ControllerBase
    {
        [HttpGet]
        [Authorize(Policy = "ReadOrder")]
        public IActionResult Get()
        {
            return new JsonResult(from c in User.Claims select new { c.Type, c.Value });
        }
        [HttpPost]
        [Authorize(Policy = "WriteOrder")]
        public IActionResult Post()
        {
            return new JsonResult(from c in User.Claims select new { c.Type, c.Value });
        }
    }

客户端

// 仅申请了读订单权限,所有只能调用资源服务器中`ReadOrder`授权策略的接口,如果调用Post接口,会返回403
var tokenResponse = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest
{
    Address = disco.TokenEndpoint,
    ClientId = "client",
    ClientSecret = "secret",
    Scope = "Order.Read"
}) ;
var apiClient = new HttpClient();
apiClient.SetBearerToken(tokenResponse.AccessToken);
var response = await apiClient.GetAsync("http://localhost:5001/order");

参考:https://cloud.tencent.com/developer/article/1977306

posted @   .Neterr  阅读(192)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了

喜欢请打赏

扫描二维码打赏

了解更多

点击右上角即可分享
微信分享提示