json Keycloak - .net core 7 jwt身份验证权限验证错误

gblwokeq  于 2023-02-26  发布在  .NET
关注(0)|答案(1)|浏览(170)

我已为用户提供了必要的权限,其内容如下所示我收到的令牌内容

{
  "exp": 1676888952,
  "iat": 1676888652,
  "jti": "e9c4cdd9-6ad2-4d26-a031-e5d35bc83439",
  "iss": "http://localhost:2011/realms/TestInventoryRealm",
  "aud": "testcompany-inventory-client",
  "sub": "022a83d1-42e3-40b2-ac11-542d87c5672f",
  "typ": "Bearer",
  "azp": "testcompany-inventory-client",
  "session_state": "24f85a76-0637-4dd7-8b8c-0ac1ae2afb66",
  "acr": "1",
  "realm_access": {
    "roles": [
      "offline_access",
      "default-roles-testcompanyinventoryrealm",
      "Super Role",
      "uma_authorization"
    ]
  },
  "resource_access": {
    "realm-management": {
      "roles": [
        "view-identity-providers",
        "view-realm",
        "manage-identity-providers",
        "impersonation",
        "realm-admin",
        "create-client",
        "manage-users",
        "query-realms",
        "view-authorization",
        "query-clients",
        "query-users",
        "manage-events",
        "manage-realm",
        "view-events",
        "view-users",
        "view-clients",
        "manage-authorization",
        "manage-clients",
        "query-groups"
      ]
    },
    "broker": {
      "roles": [
        "read-token"
      ]
    },
    "testcompany-inventory-client": {
      "roles": [
        "Super Admin Role",
        "Computing Role",
        "uma_protection",
        "Admin Role",
        "User Role"
      ]
    },
    "account": {
      "roles": [
        "manage-account",
        "view-applications",
        "view-consent",
        "view-groups",
        "manage-account-links",
        "delete-account",
        "manage-consent",
        "view-profile"
      ]
    }
  },
  "authorization": {
    "permissions": [
      {
        "scopes": [
          "create:company",
          "update:company",
          "get:company",
          "delete:company"
        ],
        "rsid": "f2f036b2-4921-4e2b-9216-996d8cc5a349",
        "rsname": "Company Resource"
      },
      {
        "rsid": "c59c75c9-3bbe-4a1c-8671-71e3d4b975fc",
        "rsname": "Default Resource"
      }
    ]
  },
  "scope": "openid profile email",
  "sid": "24f85a76-0637-4dd7-8b8c-0ac1ae2afb66",
  "email_verified": false,
  "name": "test user",
  "preferred_username": "testuser001",
  "given_name": "test",
  "family_name": "user",
  "email": "testuser@gmail.com"
}

应用程序设置

"Keycloak": {
"ServerRealm": "http://localhost:2011/realms/TestCompanyInventoryRealm",
"Metadata": "http://localhost:2011/realms/TestCompanyInventoryRealm/.well-known/openid-configuration",
"ClientId": "testcompany-inventory-client",
"ClientSecret": "faYwQ8ttVGO7R5wxVGrrZDqqPUCgWL7B",
"TokenExchange": "http://localhost:2011/realms/TestCompanyInventoryRealm/protocol/openid-connect/token",
"Audience": "testcompany-inventory-client",
"PublicKey": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjdT3dINxLFTnY8kxDPqfoh9U+TjUdisjG71RMpD6Wnd0wX64E9HeRaVxwPURDpUokoGVsVD++V8/U4aQRH3AbGzyw+90rKdPQEEAIkO/gcq8/1ppXojFX+qVT3N4/+4h/PPulwYZeO5FYoRoJAR5t4RXln4+ehOT6ShMKE/9Nxm41ijb/aUaOInp0mWO1kodn//qjqs0tZEU4YsOqeqL8ReM0/+IzYHZlyEZ11cjisxtH0fv5XI9y1C6IuRK55Iwf3yzQrDwmGQfuD3gyzs3v+WcGVdMT4e+9/QqE76WPscUwbZMNWwc0nTS4Vm+VXS5uwCcoYnRWHYY+Pw3E5ljGQIDAQAB"

}

程序.cs

我在应用程序的主要区域中使用如下定义开始项目。

var builder = WebApplication.CreateBuilder(args);


    builder.Services.AddControllers(options =>
    {
        options.Filters.Add(new ValidateFilterAttribute());
    }).AddJsonOptions(options =>
    {
        options.JsonSerializerOptions.IgnoreReadOnlyFields = true;
        options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault | JsonIgnoreCondition.WhenWritingNull;
    });

    builder.Services.Configure<ApiBehaviorOptions>(options =>
    {
        options.SuppressModelStateInvalidFilter = true;
    });
    builder.Services.AddEndpointsApiExplorer();

    //Custom FluentValidation
    builder.Services.AddCustomApplicationServices();


    #region Swagger
    builder.Services.AddSwaggerGen(c =>
    {
        c.SwaggerDoc("v1", new OpenApiInfo { Title = "InventoryManagement.API", Version = "v1" });
        c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
        {
            Name = "Authorization",
            Type = SecuritySchemeType.ApiKey,
            Scheme = "Bearer",
            BearerFormat = "JWT",
            In = ParameterLocation.Header,
            Description = "JWT Authorization header using the Bearer scheme. \r\n\r\n Enter 'Bearer' [space] and then your token in the text input below.\r\n\r\nExample: \"Bearer 1safsfsdfdfd\"",
        });
        c.AddSecurityRequirement(new OpenApiSecurityRequirement {
            {
                new OpenApiSecurityScheme {
                    Reference = new OpenApiReference {
                        Type = ReferenceType.SecurityScheme,
                            Id = "Bearer"
                    }
                },
                new string[] {}
            }
        });
    });
    #endregion





    #region JWT
    builder.Services
        .AddAuthentication(auth =>
        {
            auth.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            auth.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        }).AddJwtBearer(options =>
        {
            options.RequireHttpsMetadata = false;
            options.Authority = builder.Configuration["Keycloak:ServerRealm"];
            options.Audience = "testcompany-inventory-client";
            options.IncludeErrorDetails= true;
            options.SaveToken = true; 

            options.TokenValidationParameters = new()
            {
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidateLifetime = true,
                ValidateIssuerSigningKey = true,
                ValidIssuer = builder.Configuration["Keycloak:ServerRealm"],
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Keycloak:PublicKey"])),
            };
        });

    builder.Services.AddAuthorization(opts =>
    {
        opts.AddPolicy("create:company", policy =>
        {
            policy.RequireClaim("scope", new[] { "create:company", "get:company", "update:company", "delete:company" });
        });
    });
    #endregion

    #region Dependencies
    builder.Services.AddScoped<IUnitOfWork, UnitOfWork>();
    builder.Services.AddScoped(typeof(IGenericRepository<>), typeof(GenericRepository<>));
    builder.Services.AddScoped(typeof(IService<>), typeof(Service<>));
    builder.Services.AddScoped(typeof(NotFoundFilter<>));
    builder.Services.AddAutoMapper(typeof(AutoMapperProfile));
    #endregion


    #region Sql Server Connection
    builder.Services.AddDbContext<DataContext>(x =>
    {
        x.UseSqlServer(builder.Configuration.GetConnectionString("IMDbConnection"), options =>
        {
            options.MigrationsAssembly(Assembly.GetAssembly(typeof(DataContext)).GetName().Name);
        });
    });
    #endregion

    builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
    builder.Host.ConfigureContainer<ContainerBuilder>(containerBuilder => containerBuilder.RegisterModule(new RepositoryServiceModule()));



    var app = builder.Build();
    if (app.Environment.IsDevelopment())
    {
        app.UseSwagger();
        app.UseSwaggerUI();
    }
    app.UseHttpsRedirection();

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

    app.MapControllers().RequireAuthorization();

    app.UseCustomException();

    app.Run();

公司财务总监.cs

[Authorize(AuthenticationSchemes = "Bearer", Roles = "Super Admin Role", Policy = "company")]
  public class CompanyController : CustomBaseController
  { }

但即使它是允许的,它也不能以任何方式进行认证。我错过了一个地方吗?

u0sqgete

u0sqgete1#

如果您得到一个401错误状态代码,那么这通常意味着您的令牌未被接受(身份验证)。
如果你得到一个403错误,那么这意味着你不被允许在(授权)
对此进行调试的一种方法是在AddJwtBearer中将此标志设置为true:

options.IncludeErrorDetails = true;

如果这样做,WWW-Authenticate报头将包括拒绝令牌的原因,例如:

HTTP/1.1 401 Unauthorized
Date: Sun, 02 Aug 2020 11:19:06 GMT
WWW-Authenticate: Bearer error="invalid_token", error_description="The signature is invalid"

代码中的另一个问题是这两个代码的顺序不对:

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

你应该总是在授权之前进行身份验证,否则就没有任何意义了。
如果出现403 Forbiddn错误,那么这是由授权模块引起的,为了解决这个问题,我通常创建一个action方法,它允许匿名请求,并且只返回在用户对象中找到的声明:

[AllowAnonymous]
    [Route("/tokenapi/getidentity")]
    public IActionResult Get()
    {
        var result = new Result();

        if (User != null)
        {
            result.Name = User.Identity?.Name ?? "Unknown Name";
            result.Claims = (from c in User.Claims select c.Type + ":" + c.Value).ToList();
        }

        return new JsonResult(result);
    }

如果缺少作用域声明,那么您需要显式地将其添加到User对象,使用类似于以下内容的语句:

options.ClaimActions.MapUniqueJsonKey("scope", "scope");

相关问题