#c# #asp.net-core #asp.net-web-api #identityserver4
#c# #asp.net-core #asp.net-web-api #identityserver4
Вопрос:
Я использую Asp.net Ядро 3.1 Веб-Api для создания Api и использования сервера идентификации 4 (3.1.2) с asp.net ядро идентификации в одном проекте (оба в одном проекте) Для аутентификации пользователя. Сервер идентификации 4 генерирует токен доступа, но при вызове Api с Postman каждый раз возвращает 401. Это конфигурация моего сервера идентификации 4:
"IdentityServerSetting": {
"IdentityServerAuthority": "https://localhost:5000",
"IdentityResources": [
"openID"
],
"ApiResources": [
{
"Name": "MadPay",
"DisplayName": "MadPay Api",
"UserClaims": [
"name",
"Email"
]
}
],
"Client": [
{
"AccessTokenLifeTime": 3600,
"AllowedGrantTypes": "password",
"ClientId": "angular",
"AlwaysIncludeUserClaimsInIdToken": "true",
"AlwaysSendClientClaims": "true",
"AllowCorsOrigins": [ "https://localhost:5000" ],
"RequireClientSecret": "false",
"AllowedScopes": [ "OpenId", "MadPay" ],
"AllowOfflineAccess": "true"
}
]
}
Это мой конфигурационный сервис
public void ConfigureServices(IServiceCollection services)
{
services.Configure<JwtConfig>(_configuration.GetSection(nameof(JwtConfig)));
services.Configure<IdentityServerSetting>(_configuration.GetSection(nameof(IdentityServerSetting)));
services.AddScoped<IUnitOfWork, UnitOfWork<ApplicationDBContext>>();
services.AddMapperConfigurations();
services.AddServices();
services.AddDbContext<ApplicationDBContext>(opt =>
{
opt.UseSqlServer(_configuration.GetConnectionString("ApplicationConnection"));
});
services.AddMvcCore(opt => opt.EnableEndpointRouting = false)
.SetCompatibilityVersion(CompatibilityVersion.Version_3_0)
.AddAuthorization()
.AddNewtonsoftJson(options =>
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
services.AddResponseCaching();
services.AddIdentityServerConfig(_identityServerSetting);
services.AddApiAuthorization();
services.AddCors();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.Configure<ApiBehaviorOptions>(options =>
{
options.SuppressModelStateInvalidFilter = true;
});
}
Это моя настройка
public void Configure(IApplicationBuilder app, IHostEnvironment env)
{
IdentityModelEventSource.ShowPII = true;
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
//app.UseHsts();
app.UseCors(i => i.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());
app.AddExceptionHandling();
app.UseResponseCaching();
app.UseIdentityServer();
app.UseHttpContext();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "api/{controller}/{action}/{id?}");
});
}
AddApiAuthorization Fuction
public static void AddApiAuthorization(this IServiceCollection services)
{
services.AddAuthentication(options =>
{
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(opt =>
{
opt.Authority = "https://localhost:5000";
opt.RequireHttpsMetadata = false;
//opt.Audience = "MadPay";
opt.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = false
};
});
services.AddScoped<IAuthorizationHandler, PermissionAuthorizationHandler>();
services.AddAuthorization(option =>
option.AddPolicy("Permission", builder =>
builder.AddRequirements(new PermissionRequirement()).RequireAuthenticatedUser()
)
);
}
Функция AddIdentityServerConfig
public static void AddIdentityServerConfig(this IServiceCollection services, IdentityServerSetting config)
{
var finalConfig = MapJsonToConfig(config);
services.AddIdentity<User, Role>(opt =>
{
opt.Password.RequireLowercase = false;
opt.Password.RequireUppercase = false;
opt.Password.RequireNonAlphanumeric = false;
opt.User.RequireUniqueEmail = true;
opt.SignIn.RequireConfirmedAccount = true;
opt.SignIn.RequireConfirmedEmail = true;
})
.AddEntityFrameworkStores<ApplicationDBContext>()
.AddUserManager<AppUserManager>()
//.AddSignInManager<AppSignInManager>()
.AddErrorDescriber<AppErrorDescriberService>()
.AddDefaultTokenProviders();
services.AddIdentityServer(options =>
{
options.Events.RaiseErrorEvents = true;
options.Events.RaiseInformationEvents = true;
options.Events.RaiseFailureEvents = true;
options.Events.RaiseSuccessEvents = true;
})
.AddDeveloperSigningCredential()
.AddInMemoryIdentityResources(finalConfig.IdentityResources)
.AddInMemoryApiResources(finalConfig.Apis)
.AddInMemoryClients(finalConfig.Clients)
.AddAspNetIdentity<User>()
.AddResourceOwnerValidator<AppIdentityPasswordValidator<User>>();
}
Это моя загрузка из токена доступа
{
"nbf": 1597823415,
"exp": 1597827015,
"iss": "https://localhost:5000",
"aud": "MadPay",
"client_id": "angular",
"sub": "1",
"auth_time": 1597823413,
"idp": "local",
"name": "osali",
"scope": [
"MadPay",
"offline_access"
],
"amr": [
"pwd"
]
}
И для Call Api используйте этот URL: https://localhost:5000 /…
И отправить токен в заголовке авторизации: Bearer ….
я думаю, что выпущенный токен доступа не является проблемой. Я потратил несколько дней и не могу понять, почему не работает, и очень смущен, что не так!!
Комментарии:
1. можете ли вы опубликовать копию токена и как выглядит ваш запрос postman? Используете ли вы какие-либо политики авторизации в API? или как защищены контроллеры API?
2. Я отредактировал свой вопрос и добавил больше деталей.
3. Я обновил свой ответ ниже, это помогает?
Ответ №1:
Вы могли бы установить для всех параметров проверки токена значение false, а затем включить их один за другим, чтобы увидеть, что вызывает ошибку.
options.TokenValidationParameters.ValidateAudience = false;
options.TokenValidationParameters.ValidateIssuer = false;
options.TokenValidationParameters.ValidateIssuerSigningKey = false;
options.TokenValidationParameters.ValidateLifetime = false;
options.TokenValidationParameters.ValidateTokenReplay = false;
Вы также можете попробовать включить следующее и проверить ответ от API в postman или Fiddler.
//True if token validation errors should be returned to the caller.
options.IncludeErrorDetails = true;
Как защищены контроллеры API? Используете ли вы какие-либо политики авторизации?
При запуске вашего API вы не должны использовать IdentityServer, вместо этого вы должны использовать метод AddMyJwtBearer. и в вашем методе настройки вы должны использовать:
app.UseAuthentication();
app.UseAuthorization();
Вот пример класса startup.cs для типичного API:
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMyJwtBearer(options =>
{
options.Audience = "payment";
options.Authority = "https://localhost:6001/";
//True if token validation errors should be returned to the caller.
options.IncludeErrorDetails = true;
//If the signing key is not found, do a refresh from the JWKS endpoint
//This allows for automatic recovery in the event of a key rollover
options.RefreshOnIssuerKeyNotFound = true;
//Gets or sets if HTTPS is required for the metadata address or authority.
//Should always be true in production!
options.RequireHttpsMetadata = true;
//True if the token should be stored in the AuthenticationProperties
//after a successful authorization.
options.SaveToken = true;
//Parameters
options.TokenValidationParameters.ClockSkew = TimeSpan.FromMinutes(5);
options.TokenValidationParameters.NameClaimType = "name";
options.TokenValidationParameters.RoleClaimType = "role";
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}
В дополнение к этому ответу я написал сообщение в блоге, в котором более подробно рассматривается эта тема:
Устранение проблем с аутентификацией JwtBearer в ASP.NET Ядро
Комментарии:
1. Это не работает, я добавляю проект в Gitlab, ссылка , чтобы увидеть весь код. Спасибо
2. В проекте Api используйте IdentityServer4 И Asp.net Общая идентификация ядра, если не использовать IdentityServer, то localhost: 5000 / connect / token не может получить доступ и не может сгенерировать токен
3. эта ошибка не помогает?trce: IdentityServer4.Hosting. EndpointRouter[0] Запись конечной точки не найдена для пути запроса: /api /WeatherForecast
4. в моем примере попробуйте удалить часть /api / из URL. это помогает? или измените мой шаблон на шаблон: «api / {controller} / {action} / {id?}»); Я вижу, что ваш код в GitLab использует старый ASP.NET Основной стиль кодирования. Более современно использовать app.UseRouting(); и app. Используйте конечные точки ().
5. Не исправлено! Мой URL-адрес Api и URL-адрес сервера идентификации одинаковы: localhost: 5000 и оба используют https, это неправильно??
Ответ №2:
вы пропускаете ниже :-
app.UseAuthentication();
app.UseAuthorization();
можете ли вы добавить выше в метод настройки startup.cs в api и попробовать?
Комментарии:
1. @AliBelyani- к какой конечной точке api вы обращаетесь? если это конечная точка weatherForecast get, вы можете захотеть проверить атрибут разрешения, если это дает вам желаемый результат.