问题描述
我一直在尝试将Identity Server 4与SPA应用程序集成.我可以使用API来授权应用程序,但是在授权之后,尽管User.Claims
总是empty
,但是我已经在范围中添加了Claims.
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.
- Project.Auth(使用Identity Server 4)
- Project.Admin
- Project.Data(我的上下文和迁移所在的位置)
- Project.Domain(Enities)
- Project.Service(存储库和ViewModel)
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();
}
Identity Server Setup
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)
}
}
};
}
Client
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")
IdentityResources
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"}
}
};
}
Decode Token
{
"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之前,Claims和User一直具有该值.
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添加到Context和其他服务中时.我的理赔信息丢失了.但是,我仍然通过了身份验证,它正在通过我的授权过滤器".
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:
- 有对
IdentityServer4.AccessTokenValidation
的重复引用. -
我在我的API
ConfigureServices
- There was the Duplicate references to
IdentityServer4.AccessTokenValidation
. I was missing the
DefaultChallengeScheme
on my APIConfigureServices
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空的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!