Identity Server 4 在 API 上声明为空 [英] Identity Server 4 Claims empty on API

查看:20
本文介绍了Identity Server 4 在 API 上声明为空的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在尝试将 Identity Server 4 与 SPA 应用程序集成.我能够在 API 中授权应用程序,但在授权之后 User.Claims 总是 empty 尽管我已经添加了范围中的声明.

I have been trying to Integrate Identity Server 4 with SPA application. I am able to Authorize the Application in API but after the authorization the User.Claims are always empty though i have added the Claims in Scopes.

我在带有实体框架核心的 API 中使用 Asp.net Identity.

I am using Asp.net Identity in API with entity framework core.

我的项目分布在不同的项目中.

My project are distributed in different projects.

  1. Project.Auth(使用 Identity Server 4)
  2. Project.Admin
  3. Project.Data(我的上下文和迁移所在)
  4. Project.Domain(实体)
  5. Project.Service(存储库和视图模型)

Startup.cs 对于 Project.Admin

Startup.cs For Project.Admin

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<MyContext>(options =>
                options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

        services.AddAuthorization();

        services.AddIdentity<User, IdentityRole<Guid>>()
            .AddEntityFrameworkStores<MyContext>()
            .AddDefaultTokenProviders();

        services.AddAuthentication("Bearer")
            .AddIdentityServerAuthentication(options =>
            {
                options.Authority = "https://localhost:44305";
                options.RequireHttpsMetadata = false;
                options.ApiName = "api1";
            });

        services.AddCors(options =>
        {
            options.AddPolicy("default", policy =>
            {
                policy.WithOrigins("http://localhost:8080")
                    .AllowAnyHeader()
                    .AllowAnyMethod();
            });
        });

        services.AddScoped(typeof(IRepository<>), typeof(EfRepository<>));
        services.AddScoped<IContractService, ContractService>();
        services.AddScoped<IClientService, ClientService>();

        services.AddAutoMapper(mapperConfig => mapperConfig.AddProfiles(GetType().Assembly));


        services.AddMvcCore()
            .AddJsonFormatters();
    }

身份服务器设置

services.AddIdentityServer()
    .AddDeveloperSigningCredential()
    .AddConfigurationStore(options =>
    {
        options.ConfigureDbContext = builder =>
            builder.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
                sql => sql.MigrationsAssembly(typeof(MyContext).GetTypeInfo().Assembly.GetName().Name));
    })
    .AddOperationalStore(options =>
    {
        options.ConfigureDbContext = builder =>
            builder.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
                sql => sql.MigrationsAssembly(typeof(MyContext).GetTypeInfo().Assembly.GetName().Name));
    }).AddAspNetIdentity<User>();

TestUser.cs

public class TestUsers
{
    public static List<TestUser> Users = new List<TestUser>
    {
        new TestUser{SubjectId = Guid.NewGuid().ToString(), Username = "alice", Password = "alice",
            Claims =
            {
                new Claim(JwtClaimTypes.Name, "Alice Smith"),
                new Claim(JwtClaimTypes.Role,"Admin"),
                new Claim(JwtClaimTypes.GivenName, "Alice"),
                new Claim(JwtClaimTypes.FamilyName, "Smith"),
                new Claim(JwtClaimTypes.Email, "AliceSmith@email.com"),
                new Claim(JwtClaimTypes.EmailVerified, "true", ClaimValueTypes.Boolean),
                new Claim(JwtClaimTypes.WebSite, "http://alice.com"),
                new Claim(JwtClaimTypes.Address, @"{ 'street_address': 'One Hacker Way', 'locality': 'Heidelberg', 'postal_code': 69118, 'country': 'Germany' }", IdentityServer4.IdentityServerConstants.ClaimValueTypes.Json)
            }
        }
    };
}

客户端

new Client
{
    ClientId = "js",
    ClientName = "JavaScript Client",
    AllowedGrantTypes = GrantTypes.Implicit,
    AllowAccessTokensViaBrowser = true,
    AlwaysIncludeUserClaimsInIdToken = true,
    RedirectUris =            new List<string> {"http://localhost:8080/silent","http://localhost:8080/authredirect"},
    PostLogoutRedirectUris =   { "http://localhost:8080" },
    AllowedCorsOrigins =     { "http://localhost:8080" },

    AllowedScopes =
    {
        IdentityServerConstants.StandardScopes.OpenId,
        IdentityServerConstants.StandardScopes.Profile,
        "api1",
        "role"
    }
}

ApiResource

new ApiResource("api1", "My API")

身份资源

public static IEnumerable<IdentityResource> GetIdentityResources()
{
    return new List<IdentityResource> {
        new IdentityResources.OpenId(),
        new IdentityResources.Profile(),
        new IdentityResources.Email(),
        new IdentityResource {
            Name = "role",
            UserClaims = new List<string> {"role"}
        }
    };
}

解码令牌

{
  "nbf": 1525602392,
  "exp": 1525605992,
  "iss": "https://localhost:44305",
  "aud": [
    "https://localhost:44305/resources",
    "api1"
  ],
  "client_id": "js",
  "sub": "c81ce899-77d9-4c34-ab31-b456129ee762",
  "auth_time": 1525601959,
  "idp": "local",
  "scope": [
    "openid",
    "profile",
    "role",
    "api1"
  ],
  "amr": [
    "pwd"
  ]
}

为什么 API 能够授权和验证请求,但没有关于用户和声明的详细信息?我错过了 API 启动课程的任何内容吗?或者启动类的优先级存在一些错误配置.

Why the API is able to authorize and authenticate the Request but no Details on User and Claims? Did i missed anything on the API startup class? or there is some misconfiguration on the precedence on the startup class.

在我为启动类添加上下文和服务的 DI 之前,声明和用户曾经具有值.

The Claims and User used to have the value before i added the DI for Context and Services on the Startup Class.

我再次尝试删除对 Project.Service 的引用,并从 Project.Admin 中的 Statrup 类中删除所有内容.我能够获得索赔信息.如下图.

I tried again by removing the references to Project.Service and removing every thing from the Statrup class in Project.Admin. I was able to get the Claim information. As shown below.

但是,当我将 DI 添加到上下文和其他服务时.我的索赔信息丢失了.但是我仍然通过了身份验证并且它正在通过我的授权过滤器.

However when i add the DI to Context and other services. My Claim info got lost. However i am still authenticated and it is passing my Authorize Filter.

当我在我的应用程序上检查日志时,我发现了一个错误

Edited: When i was checking the log on my application i found a error

Identity.Application"未通过身份验证.失败消息:取消保护票证失败"

推荐答案

我已经找到了针对此问题的解决方案.我的代码中遗漏了几件事:

I have found my Solution for this problem. I was missing couple of things on my code:

  1. 存在对 IdentityServer4.AccessTokenValidation 的重复引用.
  2. 我的 API ConfigureServices

services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = "oidc";
})
.AddIdentityServerAuthentication(options =>
{
  options.Authority = "https://localhost:44305";
  options.RequireHttpsMetadata = false;
  options.ApiName = "api1";
});

所以我的配置服务变成了下面这样:

So my Configure Service became like below:

 public void ConfigureServices(IServiceCollection services)
{

    services.AddMvcCore().AddAuthorization().AddJsonFormatters();

    var connectionString = Configuration.GetConnectionString("DefaultConnection");
    services.AddDbContext<MyContext>(o => o.UseSqlServer(connectionString));
    services.AddIdentity<User, IdentityRole<Guid>>().AddEntityFrameworkStores<MyContext>().AddDefaultTokenProviders();


    services.AddAuthentication(
        options =>
        {
            options.DefaultAuthenticateScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = "oidc";
        })
    .AddIdentityServerAuthentication(options =>
    {
        options.Authority = "https://localhost:44305";
        options.RequireHttpsMetadata = false;
        options.ApiName = "api1";

    });

    services.AddCors(options =>
    {
        // this defines a CORS policy called "default"
        options.AddPolicy("default", policy =>
        {
            policy.WithOrigins("http://localhost:8080")
                .AllowAnyHeader()
                .AllowAnyMethod();
        });
    });
    services.AddScoped(typeof(IRepository<>), typeof(EfRepository<>));
    services.AddScoped<IContractService, ContractService>();
    services.AddScoped<IClientService, ClientService>();

    services.AddAutoMapper(mapperConfig => mapperConfig.AddProfiles(GetType().Assembly));

}

更改以上两件事解决了我丢失声明和Authorized 没有持有者令牌的问题.

Changing above two things solved my problem for missing claims and Authorized without the Bearer Token.

这篇关于Identity Server 4 在 API 上声明为空的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆