Я внедряю авторизацию JWT в Asp.Net, но у меня возникла проблема. Когда я пытаюсь получить доступ к методу Dashboard / Home, я всегда получаю ответ «401 Unauthorized». По моим исследованиям могу сказать, что запрос не может пройти
[Authorize(Policy = "ApiUser")]
Но, комментируя это утверждение, я получаю здесь ошибку
var userId = _caller.Claims.Single(c => c.Type == "id");
В котором говорится, что последовательность не содержит соответствующих элементов, и если я напечатаю
_httpContextAccessor.HttpContext.User.Claims
Я в основном получаю '[]'.
Также я хочу, чтобы вы заметили, что токен
правильный
Я тестирую приложение с помощью почтальон
Я наложил эту ошибку на два дня и очень рассчитываю на вашу помощь. Скажите, нужен ли какой-нибудь дополнительный код.
Код:
Контроллер панели приборов:
[Authorize(Policy = "ApiUser")]
[Route("api/[controller]/[action]")]
public class DashboardController : Controller
{
private readonly ClaimsPrincipal _caller;
private readonly BackendContext _appDbContext;
private readonly IHttpContextAccessor _httpContextAccessor;
public DashboardController(UserManager<AppUser> userManager, BackendContext appDbContext, IHttpContextAccessor httpContextAccessor)
{
_caller = httpContextAccessor.HttpContext.User;
_appDbContext = appDbContext;
_httpContextAccessor = httpContextAccessor;
}
// GET api/dashboard/home
[HttpGet]
public async Task<IActionResult> Home()
{
// retrieve the user info
//HttpContext.User
//return new OkObjectResult(_httpContextAccessor.HttpContext.User.Claims);
var userId = _caller.Claims.Single(c => c.Type == "id");
var customer = await _appDbContext.Customers.Include(c => c.Identity).SingleAsync(c => c.Identity.Id == userId.Value);
return new OkObjectResult(new
{
Message = "This is secure API and user data!",
customer.Identity.FirstName,
customer.Identity.LastName,
customer.Identity.PictureUrl,
customer.Identity.FacebookId,
customer.Location,
customer.Locale,
customer.Gender
});
}
}
Запуск:
public class Startup
{
private const string SecretKey = "iNivDmHLpUA223sqsfhqGbMRdRj1PVkH"; // todo: get this from somewhere secure
private readonly SymmetricSecurityKey _signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(SecretKey));
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddIdentity<IdentityUser, IdentityRole>()
.AddEntityFrameworkStores<BackendContext>()
.AddDefaultTokenProviders();
services.AddDbContext<BackendContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
b => b.MigrationsAssembly("Backend")));
services.AddSingleton<IJwtFactory, JwtFactory>();
var jwtAppSettingOptions = Configuration.GetSection(nameof(JwtIssuerOptions));
// Configure JwtIssuerOptions
services.Configure<JwtIssuerOptions>(options =>
{
options.Issuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)];
options.Audience = jwtAppSettingOptions[nameof(JwtIssuerOptions.Audience)];
options.SigningCredentials = new SigningCredentials(_signingKey, SecurityAlgorithms.HmacSha256);
});
var tokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)],
ValidateAudience = true,
ValidAudience = jwtAppSettingOptions[nameof(JwtIssuerOptions.Audience)],
ValidateIssuerSigningKey = true,
IssuerSigningKey = _signingKey,
RequireExpirationTime = false,
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero
};
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(configureOptions =>
{
configureOptions.ClaimsIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)];
configureOptions.TokenValidationParameters = tokenValidationParameters;
configureOptions.SaveToken = true;
});
// api user claim policy
services.AddAuthorization(options =>
{
options.AddPolicy("ApiUser", policy => policy.RequireClaim(Constants.Strings.JwtClaimIdentifiers.Rol, Constants.Strings.JwtClaims.ApiAccess));
});
// add identity
var builder = services.AddIdentityCore<AppUser>(o =>
{
// configure identity options
o.Password.RequireDigit = false;
o.Password.RequireLowercase = false;
o.Password.RequireUppercase = false;
o.Password.RequireNonAlphanumeric = false;
o.Password.RequiredLength = 6;
});
builder = new IdentityBuilder(builder.UserType, typeof(IdentityRole), builder.Services);
builder.AddEntityFrameworkStores<BackendContext>().AddDefaultTokenProviders();
services.AddAutoMapper();
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.TryAddSingleton<IActionContextAccessor, ActionContextAccessor>();
services.AddDbContext<BackendContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
b => b.MigrationsAssembly("Backend")));
services.AddTransient<IStoreService, StoreService>();
services.AddMvc();//.AddFluentValidation(fv => fv.RegisterValidatorsFromAssemblyContaining<Startup>());
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseAuthentication();
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseMvc();
}
}
Константы (используются при запуске):
public static class Constants
{
public static class Strings
{
public static class JwtClaimIdentifiers
{
public const string Rol = "rol", Id = "id";
}
public static class JwtClaims
{
public const string ApiAccess = "api_access";
}
}
}