【发布时间】:2020-06-05 19:52:14
【问题描述】:
我正在使用 Blazor Server 应用程序通过 Identity Server 4 进行身份验证,并可以访问 asp.net core 3.1 API。在本地,我有一个设置在端口 5000 上使用 Identity Server,在 5001 上使用 API,在 5002 上使用我的 Blazor 应用程序。
在我们的测试服务器上,我们将这三个服务器都托管在 IIS 中(Blazor 在一台服务器上,API 和 Identity Server 在另一台服务器上)。访问 Authorize 标记的控制器时,我得到 401 Unauthorized。我能够登录,并且我知道 API 仍然可以访问,因为并非所有控制器都需要授权并且数据可以通过。另外,我知道有一个令牌,因为我曾经将它打印到页面上。
在我们的测试环境中,API 不再接受 Identity Server 生成的令牌的原因可能是什么?
这是我的代码示例,如果需要,会很高兴添加更多:
授权控制器
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[Route("api/[controller]")]
[ApiController]
public class Controller : ControllerBase
API 资源
public static IEnumerable<ApiResource> Apis =>
new ApiResource[]
{
new ApiResource("Api", "MyApi")
};
客户端设置
public static IEnumerable<Client> Clients =>
new List<Client>
{
//Client
new Client
{
ClientId = "Client",
ClientSecrets = { new Secret("secret".Sha256()) },
AllowedGrantTypes = GrantTypes.HybridAndClientCredentials,
// where to redirect to after login
RedirectUris = { "http://location:5002/signin-oidc" },
// where to redirect to after logout
PostLogoutRedirectUris = { "http://location:5002/signout-callback-oidc" },
AllowedScopes = new List<string>
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.OfflineAccess,
"Api"
},
AllowOfflineAccess = true
}
};
API 配置
services.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", options =>
{
options.Authority = AuthUrl; // IS loc
options.Audience = "Api";
});
客户端配置
services.AddSingleton<IDiscoveryCache>(sp =>
{
var factory = sp.GetRequiredService<IHttpClientFactory>();
return new DiscoveryCache(
AuthUrl,
() => factory.CreateClient());
});
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddOpenIdConnect("oidc", options =>
{
options.Authority = AuthUrl;
options.ClientId = ClientID;
options.ClientSecret = ClientSecret;
options.ResponseType = "code id_token";
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
// part 3
options.Scope.Add("openid");
options.Scope.Add("offline_access");
options.Scope.Add("Api");
options.RequireHttpsMetadata = false;
});
这是我使用签名凭据的方式
// not recommended for production - you need to store your key material somewhere secure
if (Environment.IsDevelopment())
{
builder.AddDeveloperSigningCredential();
}
else
{
X509Certificate2 cert = null;
using (var certStore = new X509Store(StoreName.My, StoreLocation.LocalMachine))
{
certStore.Open(OpenFlags.ReadOnly);
var certCollection = certStore.Certificates.Find(
X509FindType.FindByThumbprint,
"76588d12094bc26991faf9e3eaaa241d973fe72f", // Change this with the thumbprint of your certificate
false);
if (certCollection.Count > 0)
{
cert = certCollection[0];
}
}
builder.AddSigningCredential(cert);
}
我使用了通过 openssl 生成的自签名证书,并且我也通过不使用 .developerssigningcredentials 在开发人员环境中对其进行了测试。
【问题讨论】:
-
让我印象深刻的一件事是您的 api 配置中的受众价值。它应该是所使用的客户端的 client_id。另外,您能否在示例令牌中发布 AuthUrl 的值和一些声明?
-
link 表明 .audience 是 API 资源名称/ID? AuthUrl 在我的机器上是“Server.Address:5000”或 localhost:5000。
-
你试过邮递员来触发请求吗?
-
类似的结果。 401 Unauthorized with a given Token from Identity Server.
-
你把
http://location:5002/的引用改成服务器上的新地址了吗?
标签: c# api identityserver4 blazor asp.net-core-3.1