asp.net-core - Identity Server 4 的 API 授权不断返回 401 Unauthorized

标签 asp.net-core identityserver4 openid-connect jwt-auth

我正在使用 Identity Server 4 .Net Core 3,如果我在启动时使用标准配置,我的 API 端点不会验证访问 token ,我不断收到 401 Unauthorized,但是当我使用授权属性在 Controller 中设置身份验证方案时,我可以使用相同的 token 成功访问我的端点...

[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";
            });

最后是我的 Web 应用程序、OIDC 配置以及我如何获取访问 token :
        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();

订单在 documentation 中描述.

关于asp.net-core - Identity Server 4 的 API 授权不断返回 401 Unauthorized,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59096204/

相关文章:

c# - 使用本地 .NET Core 系统库而不是将它们添加到每个包中

json - 您可以预览 ASP.NET Core 的 appsettings.json 环境覆盖吗?

identityserver4 - 使用 AddIdentityExpressAdminUiConfiguration() 而不是 AddDefaultIdentity() 时如何指定 SignIn.RequireConfirmedAccount?

identityserver4 - 在 IdentityServer4 中, 'idsrv' 和 'idsrv.session' cookie 有什么区别?

javascript - 使用身份服务器 4 匿名访问 SignalR hub

asp.net-core - OpenId Connect更新SPA中的access_token

visual-studio - 为什么 Visual Studio 告诉我需要引用 System.Private.CoreLib?

c# - 在 ASP.NET Core 中显示只读字段

azure - ASP.NET Core 的身份验证中间件是否始终对 OpenID Connect 使用隐式流?

PayPal id_token 验证