英文:
IdentityServer - Configuring ApiResources
问题
以下是您要翻译的内容:
所以,我正在按照最新的IdentityServer/Duende官方资源中的快速入门进行操作。
从我的理解来看,Api资源实际上是api作用域和身份作用域的逻辑分组。您可以在Api资源"api"中包装3个Api作用域"apiscope1","apiscope2","apiscope3"。
在设置客户端时,您需要在范围中指定"api",这将自动为您提供apiscope1、apiscope2和apiscope3。
- 这是正确的吗?
我有两个Api:MyApi和IdentityServerApi。
MyApi的配置如下:
builder.Services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
{
var idsvrConfig = builder.Configuration.GetSection("IdentityServer").Get<IdentityServerConfiguration>();
options.Authority = idsvrConfig.Authority;
options.ClientId = idsvrConfig.ClientId;
options.ClientSecret = idsvrConfig.ClientSecret;
options.ResponseType = idsvrConfig.ResponseType;
options.Scope.Clear();
//options.Scope.AddRange(idsvrConfig.Scopes);
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("verification");
options.Scope.Add("apiResource"); //<-------当指定此范围时不起作用!!
// 其他配置选项...
});
现在是Identity Server API的配置:
var apiResources = new List<ApiResource>()
{
new ApiResource()
{
Name = "apiResource",
DisplayName ="ApiResource",
Scopes = new string[] { "test" }
}
};
var apiScopes = new List<ApiScope>()
{
new ApiScope()
{
Name = "test",
}
};
var identityResources = new List<IdentityResource>
{
new IdentityResources.OpenId(),
new IdentityResources.Profile(),
new IdentityResource()
{
Name = "verification",
UserClaims = new List<string>
{
JwtClaimTypes.Email,
JwtClaimTypes.EmailVerified
}
}
};
var clients = new List<Client>
{
new Client
{
ClientId = "api",
ClientSecrets = { new Secret(){
Value = "supersecretpass"
}},
AllowedGrantTypes = GrantTypes.Code,
// 其他客户端配置...
}
};
// 添加Identity Server服务
builder.Services.AddIdentityServer()
.AddInMemoryClients(clients)
.AddInMemoryIdentityResources(identityResources)
.AddInMemoryApiScopes(apiScopes)
.AddInMemoryApiResources(apiResources)
.AddTestUsers(TestUsers.Users);
- 当我在MyApi中添加"apiResource"范围时,为什么会出现无效范围屏幕错误,但当我从客户端请求的范围中删除它时,完整的登录/注销流程可以正常工作?
任何帮助/见解都将不胜感激。
请让我知道如果您需要更多的翻译。
英文:
So I was following the quick starts from the latest IdentityServer/Duende official resources.
From what I understood, An Api Resource is essentially logical grouping of apiscopes and identityscopes.
You can Have 3 ApiScopes "apiscope1", "apiscope2","apiscope3", wrapped in an ApiResource "api".
When setting the client, you need to specify "api" in scopes, which will automatically give you apiscope1, apiscope2, apiscope3.
1. Is this correct?
I have two Apis:
MyApi and IdentityServerApi.
MyApi is configured as follows:
builder.Services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
{
var idsvrConfig = builder.Configuration.GetSection("IdentityServer").Get<IdentityServerConfiguration>();
options.Authority = idsvrConfig.Authority;
options.ClientId = idsvrConfig.ClientId;
options.ClientSecret = idsvrConfig.ClientSecret;
options.ResponseType = idsvrConfig.ResponseType;
options.Scope.Clear();
//options.Scope.AddRange(idsvrConfig.Scopes);
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("verification");
options.Scope.Add("apiResource"); //<-------Doesn't work when this is specified!!
options.GetClaimsFromUserInfoEndpoint = idsvrConfig.GetClaimsFromUserInfoEndpoint;
options.SaveTokens = idsvrConfig.SaveTokens;
foreach (var claims in idsvrConfig.ClaimActionsMapJsonKey)
{
options.ClaimActions.MapJsonKey(claims.Key, claims.Value);
}
});
Now for the Identity Server API Configuration:
var apiResources = new List<ApiResource>()
{
new ApiResource()
{
Name = "apiResource",
DisplayName ="ApiResource",
Scopes = new string[] {"test" }
}
};
var apiScopes = new List<ApiScope>()
{
new ApiScope()
{
Name = "test",
}
};
var identityResources = new List<IdentityResource>
{
new IdentityResources.OpenId(),
new IdentityResources.Profile(),
new IdentityResource()
{
Name = "verification",
UserClaims = new List<string>
{
JwtClaimTypes.Email,
JwtClaimTypes.EmailVerified
}
}
};
var clients = new List<Client>
{
// interactive ASP.NET Core Web App
new Client
{
ClientId = "api",
ClientSecrets = { new Secret(){
Value = "supersecretpass"
}},
AllowedGrantTypes = GrantTypes.Code,
// where to redirect after login
RedirectUris = { "https://localhost:44330/signin-oidc" },
// where to redirect after logout
PostLogoutRedirectUris = { "https://localhost:44330/signout-callback-oidc" },
AllowedScopes = new List<string>
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"verification",
"apiResource",
"test"
}
}
};
// Add Identity Server services
builder.Services.AddIdentityServer()
.AddInMemoryClients(clients)
.AddInMemoryIdentityResources(identityResources)
.AddInMemoryApiScopes(apiScopes)
.AddInMemoryApiResources(apiResources)
//.AddInMemoryClients(builder.Configuration.GetSection("IdentityServer:Clients"))
//.AddInMemoryIdentityResources(builder.Configuration.GetSection("IdentityServer:IdentityResources"))
//.AddInMemoryApiScopes(builder.Configuration.GetSection("IdentityServer:ApiScopes"))
//.AddInMemoryApiResources(builder.Configuration.GetSection("IdentityServer:ApiResources"))
.AddTestUsers(TestUsers.Users);
2. Why is it that when on MyApi I add the scope "apiResource", I get an invalid scope screen error but when I remove it from the scopes requested by the client the full login/logout flow works?
Any help/insight is appreciated.
Just in case the versions make any difference, I'm running the following packages:
Both Api are running .NET 7
For MyApi: Microsoft.AspNetCore.Authentication.OpenIdConnect 7.0.5
For Idsvr: Duende.IdentityServer 6.2.3
答案1
得分: 2
你在客户端中设置了包含apiResource
字段的Scope
,但没有在服务器中配置它,导致"Invalid scope"错误,因为Scope
无法匹配。
你需要在IdentityServerApi
的Client
的AllowedScopes
中指定apiResource
:
new Client
{
ClientId = "api",
ClientSecrets = { new Secret(){
Value = "supersecretpass"
}},
AllowedGrantTypes = GrantTypes.Code,
// where to redirect after login
RedirectUris = { "https://localhost:44330/signin-oidc" },
// where to redirect after logout
PostLogoutRedirectUris = { "https://localhost:44330/signout-callback-oidc" },
AllowedScopes = new List<string>
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"verification",
"apiResource"
}
}
然后,在MyApi
中添加apiResource
作用域,你应该能够成功运行:
builder.Services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddOpenIdConnect("oidc", options =>
{
options.Authority = "<idsvr-url>";
options.ClientId = "api";
options.ClientSecret = "supersecretpass";
options.ResponseType = "code";
options.Scope.Clear();
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("verification");
options.Scope.Add("apiResource");
options.GetClaimsFromUserInfoEndpoint = true;
options.SaveTokens = true;
});
有关ApiResource
和ApiScope
的更多详细信息,你可以参考此链接。
更新:
在AllowedScopes
中添加的作用域应该是已定义的。你只在apiScopes
中定义了test
,而没有定义apiResource
。
var apiScopes = new List<ApiScope>()
{
new ApiScope()
{
Name = "test",
},
// 添加这个
new ApiScope
{
Name = "apiResource"
},
};
关于"Aud"声明,你不需要手动配置它。当你添加一个ApiResource
并指定相应的Scope
时,客户端使用这个Scope
进行请求时,获得的Token
将默认具有"Aud"声明。
例如,我添加了两个ApiResources
并指定了相应的Scope
:
new List<ApiResource>
{
new ApiResource()
{
Name = "apiResource",
DisplayName ="ApiResource",
Scopes = new string[] {"test" }
},
new ApiResource()
{
Name = "paymentApi",
DisplayName = "PaymentApi",
Scopes= new string[] {"test2"}
}
}
然后在ApiScope
中添加相应的Scope
:
new List<ApiScope>
{
new ApiScope()
{
Name = "test"
},
new ApiScope
{
Name = "apiResource"
},
new ApiScope
{
Name = "test2"
}
}
在IdentityServerApi
中配置Client
(我不确定你的ClientSecrets
是否可以验证,因为我根据官方文档进行了配置):
new Client
{
ClientId = "web",
ClientSecrets = { new Secret("secret".Sha256()) },
AllowedGrantTypes = GrantTypes.Code,
// where to redirect to after login
RedirectUris = { "https://localhost:5002/signin-oidc" },
// where to redirect to after logout
PostLogoutRedirectUris = { "https://localhost:5002/signout-callback-oidc" },
AllowedScopes = new List<string>
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"apiResource",
"test",
"test2"
}
}
在ClientApi
中:
builder.Services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddOpenIdConnect("oidc", options =>
{
options.Authority = "https://localhost:5001";
options.ClientId = "web";
options.ClientSecret = "secret";
options.ResponseType = "code";
options.Scope.Clear();
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("apiResource");
options.Scope.Add("test");
options.GetClaimsFromUserInfoEndpoint = true;
options.SaveTokens = true;
});
成功登录后,我可以看到.Token.access_token
,这是根据官方文档所建立的示例:
将这个access_token
复制并粘贴到jwt.io中,你可以看到你的ApiResource
包含在aud
中:
当我在ClientApi中添加一行:
options.Scope.Add("test2");
你可以看到"apiResource"和"paymentApi"都包含在"aud"中:
英文:
You set the Scope
containing the apiResource
field in the client, but did not configure it in the server, Invalid scope
is caused because the Scope
cannot match.
You need to specify apiResource
in AllowedScopes
of Client
in IdentityServerApi
:
new Client
{
ClientId = "api",
ClientSecrets = { new Secret(){
Value = "supersecretpass"
}},
AllowedGrantTypes = GrantTypes.Code,
// where to redirect after login
RedirectUris = { "https://localhost:44330/signin-oidc" },
// where to redirect after logout
PostLogoutRedirectUris = { "https://localhost:44330/signout-callback-oidc" },
AllowedScopes = new List<string>
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"verification",
"apiResource"
}
}
Then you add the scope apiResource
in MyApi
, you should be able to successfully run.
builder.Services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddOpenIdConnect("oidc", options =>
{
options.Authority = "<idsvr-url>";
options.ClientId = "api";
options.ClientSecret = "supersecretpass";
options.ResponseType = "code";
options.Scope.Clear();
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("verification");
options.Scope.Add("apiResource");
options.GetClaimsFromUserInfoEndpoint = true;
options.SaveTokens = true;
});
For more details about ApiResource
and ApiScope
, you can refer to this link.
Update:
The scopes added in AllowedScopes
should be defined. You only defined test
in apiScopes
, not apiResource
.
var apiScopes = new List<ApiScope>()
{
new ApiScope()
{
Name = "test",
},
//add this
new ApiScope
{
Name = "apiResource"
},
};
Regarding the "Aud" claim, you don't need to manually configure it. When you add an ApiResource
and specify the corresponding Scope
, when the client uses this Scope
to make a request, the obtained Token
will have the Aud
claim by default.
For example, I added two ApiResources
and specified the corresponding Scope
:
new List<ApiResource>
{
new ApiResource()
{
Name = "apiResource",
DisplayName ="ApiResource",
Scopes = new string[] {"test" }
},
new ApiResource()
{
Name = "paymentApi",
DisplayName = "PaymentApi",
Scopes= new string[] {"test2"}
}
};
Then add the corresponding Scope
in ApiScope
:
new List<ApiScope>
{
new ApiScope()
{
Name = "test"
},
new ApiScope
{
Name = "apiResource"
},
new ApiScope
{
Name = "test2"
}
};
Configure Client
in IdentityServerApi
(I'm not sure whether your ClientSecrets
can be verified, because I configured it according to the official document):
new Client
{
ClientId = "web",
ClientSecrets = { new Secret("secret".Sha256()) },
AllowedGrantTypes = GrantTypes.Code,
// where to redirect to after login
RedirectUris = { "https://localhost:5002/signin-oidc" },
// where to redirect to after logout
PostLogoutRedirectUris = { "https://localhost:5002/signout-callback-oidc" },
AllowedScopes = new List<string>
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"apiResource",
"test",
"test2"
}
}
In ClientApi:
builder.Services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddOpenIdConnect("oidc", options =>
{
options.Authority = "https://localhost:5001";
options.ClientId = "web";
options.ClientSecret = "secret";
options.ResponseType = "code";
options.Scope.Clear();
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("apiResource");
options.Scope.Add("test");
options.GetClaimsFromUserInfoEndpoint = true;
options.SaveTokens = true;
});
I can see .Token.access_token
after successfully logging in with the example built by referring to the official document:
Copy this access_token
and paste in jwt.io, you can see that your ApiResource
is included in the aud
:
When I add a line in ClientApi:
options.Scope.Add("test2");
You can see both apiResource
and paymentApi
are included in aud
:
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论