簡體   English   中英

Identity Server 4 的 API 授權不斷返回 401 Unauthorized

[英]API Authorization with Identity Server 4 keeps returning 401 Unauthorized

我正在使用 Identity Server 4.Net Core 3,如果我在啟動時使用標准配置,我的 API 端點不會驗證訪問令牌,我一直收到 401 Unauthorized,但是當我在具有授權屬性的控制器中設置身份驗證方案時,我可以使用相同的令牌成功訪問我的端點...

[Route("api/[controller]")]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[ApiController]
public class MyWebAPiControllerController : ControllerBase
{
.......

這是我的身份服務器配置:

//API resource       
public IEnumerable<ApiResource> Apis()
{
        var resources = new List<ApiResource>();

        resources.Add(new ApiResource("identity", "My API", new[] { JwtClaimTypes.Subject, JwtClaimTypes.Email, JwtClaimTypes.Role, JwtClaimTypes.Profile }));

        return resources;
}

我的客戶端配置:

public IEnumerable<Client> Clients()
    {

        var Clients = new List<Client>();

        Clients.Add(new Client
        {
            ClientId = "client",
            ClientSecrets = { new Secret(_securityConfig.Secret.Sha256()) },

            AllowedGrantTypes = GrantTypes.ClientCredentials,
            // scopes that client has access to
            AllowedScopes = { "identity" }
        });

        Clients.Add(new Client
        {
            ClientId = "mvc",
            ClientName = "MVC Client",

            AllowedGrantTypes = GrantTypes.HybridAndClientCredentials,
            //RequirePkce = true,
            ClientSecrets = { new Secret(_securityConfig.Secret.Sha256()) },
            RequireConsent = false,
            RedirectUris = _securityConfig.RedirectURIs,
            FrontChannelLogoutUri = _securityConfig.SignoutUris,
            PostLogoutRedirectUris = _securityConfig.PostLogoutUris,
            AllowOfflineAccess = true,
            AllowAccessTokensViaBrowser = true,
            AllowedScopes = new List<string>
                {
                    IdentityServerConstants.StandardScopes.OpenId,
                    IdentityServerConstants.StandardScopes.Profile,
                    IdentityServerConstants.StandardScopes.Email,
                    IdentityServerConstants.StandardScopes.OfflineAccess,
                    "identity"
                }

        });

        return Clients;
    } 

我的 API 配置

 services.AddAuthentication("Bearer")
            .AddJwtBearer("Bearer", options =>
            {
                options.Authority = _securityConfig.Authority;
                options.RequireHttpsMetadata = false;

                options.Audience = "identity";
            });

最后是我的網絡應用程序、OIDC 配置以及我如何獲取訪問令牌:

        services.AddAuthentication(options =>
        {
            options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = "oidc";
        }).AddCookie(options =>
            {
                options.ExpireTimeSpan = TimeSpan.FromMinutes(60);
                options.Cookie.Name = "identity_cookie";
            })
        .AddOpenIdConnect("oidc", options =>
        {
            options.Events = new OpenIdConnectEvents
            {
                OnUserInformationReceived = async ctx =>
                {
                    //Get Token here and assign to Cookie for use in Jquery
                    ctx.HttpContext.Response.Cookies.Append("bearer_config", ctx.ProtocolMessage.AccessToken);
                }
            };

            options.Authority = _securityConfig.Authority;
            options.RequireHttpsMetadata = false;

            options.ClientId = "mvc";
            options.ClientSecret = _securityConfig.Secret;
            options.ResponseType = "code id_token";
            options.SaveTokens = true;


            options.Scope.Clear();
            options.Scope.Add("openid");
            options.Scope.Add("profile");
            options.Scope.Add("email");
            options.Scope.Add("identity");
            options.Scope.Add("offline_access");

            options.ClaimActions.MapAllExcept("iss", "nbf", "exp", "aud", "nonce", "iat", "c_hash");

            options.GetClaimsFromUserInfoEndpoint = true;
            //options.SaveTokens = true;

            options.TokenValidationParameters = new TokenValidationParameters
            {
                NameClaimType = JwtClaimTypes.Name,
                RoleClaimType = JwtClaimTypes.Role,
            };


        });

關於為什么我不斷收到 401 Unauthorized 的任何想法?

根據所描述的行為,我認為這可能與中間件配置有關,更具體地說是中間件的順序。 但我不能確定,因為 Startup.Configure 在問題中不可用。

幸運的是,雅克可以確認問題確實出在訂單上。 如評論中所述:

app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseAuthentication();

這里的問題是用戶首先被授權( UseAuthorization )然后被認證( UseAuthentication )。 因此,用戶永遠無法獲得授權,因為此時它是未知的(匿名的)。 但稍后,當屬性被驗證時,用戶是已知的。 所以這就解釋了為什么會這樣。

為了解決這個問題,必須切換語句。 先對用戶進行身份驗證(識別用戶,用戶是誰?),然后對用戶進行授權:

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

該順序在文檔中進行了描述。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM