我正在重构一个单一的 .NET CORE MVC 应用程序。到目前为止我所拥有的是我添加了 IS4 并将部分逻辑从 MVC 提取到新的 API。 这就是我设置 IS4
的方式public static IEnumerable<ApiScope> GetApiScopes() =>
new List<ApiScope>
{
new ApiScope("CRMApi", "CRM API Scopes"),
};
public static IEnumerable<ApiResource> GetApiResources() =>
new List<ApiResource>
{
new ApiResource("CRMApi", "CRM API Resources")
{
Scopes = { "CRMApi" },
Enabled = true,
UserClaims = { "sub", "name", "email" },
},
};
public static IEnumerable<Client> GetClients() =>
new List<Client>
{
new Client
{
ClientId = "CRMClientMVC",
ClientName = "MVC Client",
ClientSecrets = { new Secret("MVCSecret".Sha512()) },
AllowedGrantTypes = GrantTypes.Hybrid,
RequirePkce = false,
AllowedScopes = {
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Email,
"CRMApi",
},
RedirectUris = new List<string>{ $"{Discovery.CRMClient}/signin-oidc" },
PostLogoutRedirectUris = new List<string> { $"{Discovery.CRMClient}/signout-callback-oidc" }
},
new Client
{
ClientId = "CRMNewApi",
ClientName = "CRM API",
ClientSecrets = { new Secret("CRMApi.secret".Sha256()) },
AllowedGrantTypes = GrantTypes.ResourceOwnerPasswordAndClientCredentials,
RequirePkce = false,
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Email,
"CRMApi",
},
AlwaysIncludeUserClaimsInIdToken = true
},
};
我的MVC
services.AddAuthentication(opt =>
{
opt.DefaultScheme = "Cookies";
opt.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddOpenIdConnect("oidc", opt =>
{
opt.SignInScheme = "Cookies";
opt.Authority = discoverySettings.IdentityApi;
opt.ClientId = "CRMClientMVC";
opt.ResponseType = "code id_token";
opt.SaveTokens = true;
opt.ClientSecret = "MVCSecret";
opt.GetClaimsFromUserInfoEndpoint = true;
opt.Scope.Add("email");
opt.Scope.Add("CRMApi");
});
和API:
builder.Services.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", opt =>
{
opt.RequireHttpsMetadata = false;
opt.Authority = discoverySettings.IdentityApi;
opt.Audience = "CRMApi";
});
我可以注册新用户并登录。当我转到任何子页面时,我都可以从 MVC 调用 API,这很棒。
问题
但是因为 MVC 和 API 之间的依赖关系很重要,我还必须从 API 调用 MVC。 这就是我遇到问题的地方。当我从 API 调用 MVC 时,我得到状态代码 200,但响应内容是 IS4 登录页面 html?!
<head>
...
<title>IdentityServer4</title>
...
</head>
...
这就是我在游戏机上看到的
MVC 控制台
info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]
Authorization failed. These requirements were not met:
DenyAnonymousAuthorizationRequirement: Requires an authenticated user.
2023-03-14 11:16:08.9242|INFO|Microsoft.AspNetCore.Authorization.DefaultAuthorizationService|Authorization failed. These requirements were not met:
DenyAnonymousAuthorizationRequirement: Requires an authenticated user.
IS 控制台
info: IdentityServer4.Hosting.IdentityServerMiddleware[0]
Invoking IdentityServer endpoint: IdentityServer4.Endpoints.AuthorizeEndpoint for /connect/authorize
info: IdentityServer4.ResponseHandling.AuthorizeInteractionResponseGenerator[0]
Showing login: User is not authenticated
流程通常是这样的:
我在首页点击了一些东西
这会在 MVC 中使用 [Authorize] 属性执行一些操作
MVC 调用 API
这会在具有 [Authorize] 属性的 API 中执行一些操作
但是 API 完成它的工作需要一些来自 MVC 的数据所以它调用 MVC
这会在 MVC 中执行另一个具有 [Authorize] 属性的操作 但这并不像描述的那样工作
这就是我从 API 进行调用的方式。我将 MVC 访问令牌复制到请求中
var client = _httpClientFactory.CreateClient(httpClientType.ToString());
var accessToken = await _httpContextAccessor.HttpContext.GetTokenAsync(OpenIdConnectParameterNames.AccessToken);
var authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken);
requestMessage.Headers.Authorization = authorization;
我试过什么
我从请求中删除了访问令牌,但结果是一样的。
我尝试添加 MVC 资源和范围,然后将其包含在 API 范围中,但这不起作用。可能是因为我调用 API->MVC 的方式。
new ApiResource("CRMClient", "CRM Client MVC Resources")
{
Scopes = { "CRMClient" },
Enabled = true,
UserClaims = { "sub", "name", "email" },
}
new ApiScope("CRMClient", "CRM Client MVC Scopes")
在 API 客户端中我添加了这个范围
"CRMClient"
结果还是一样。
问题
我想知道我在这里错过了什么?我应该以某种方式在启动时授权我的 API 吗?将令牌存储在某处并在请求消息中将该令牌发送到 MVC?我在这里完全无能为力。 如果我添加第二个、第三个 API 并希望所有 API 和 MVC 能够相互通信怎么办?
我可以分享更多细节,例如如果需要的话。 提前谢谢你。