我正在Asp.Net上实现JWT授权,但是在这里遇到麻烦。当我尝试访问Dashboard / Home控制器的方法时,我总是收到“ 401未经授权”响应。根据我的研究,我可以说请求无法通过
[Authorize(Policy = "ApiUser")]
但是在评论该声明时,我在这里收到一个错误
var userId = _caller.Claims.Single(c => c.Type == "id");
其中指出序列不包含任何适当的元素,如果我要打印
_httpContextAccessor.HttpContext.User.Claims
我基本上收到一个'[]'。
我也希望您注意令牌是
correct
我正在postman的帮助下测试应用程序
我在此错误上堆积了两天,真的依靠您的帮助。告诉我是否需要其他代码。
代码:
仪表板控制器:
[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";
}
}
}
答案 0 :(得分:0)
因为您的问题是由令牌生成与@foreach ($categories as $category)
<ul class="list-group">
<a data-toggle="collapse" href="#collapseExample" class="card-header list-group-item d-flex justify-content-between align-items-center">
<option value="{{ $category->id }}">{{ ucwords($category->name) }}</option>
<span class="badge badge-primary badge-pill">{{ $categories->count() }}</span>
</a>
@foreach ($category->children as $child)
<div id="collapseExample" class="collapse">
<ul class="list-group">
<option class="list-group-item" value="{{ $child->id }}">{{ ucwords($child->name) }}
</option>
</ul>
</div>
@endforeach
</ul>
@endforeach
和Issuer
的验证之间的不匹配配置引起的。
在Audience
中,您配置Startup.cs
和ValidateIssuer = true
,但是对于您提供的令牌,没有ValidateAudience = true
和iss
。
有两种尝试方法:
无法验证aud
和Issuer
Audience
或者在生成令牌时提供 var tokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false,
ValidIssuer = "Issuer",
ValidateAudience = false,
ValidAudience = "Audience",
ValidateIssuerSigningKey = true,
IssuerSigningKey = _signingKey,
RequireExpirationTime = false,
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero
};
和Issuer
。
Audience
这是一个正在运行的演示CoreJwt。
答案 1 :(得分:0)
自提出此问题以来已经过去了大约4个月,但我希望它将对将来的访问者有所帮助,我遇到了同样的问题,这是因为我错过了将app.UseAuthentication();
添加到我的{{ 1}}方法:
Configure
我也错过了将app.UseAuthentication();
//////////////////////////
app.UseHttpsRedirection();
app.UseStaticFiles();
添加到我的JwtIssuerOptions
和appsettings.json
中的事情:
appsettings.Development.json