[英].NET core JWT authorization failed?
我試圖讓 JWT 在這里工作,登錄后我的客戶端成功接收到令牌,但是當我在 /info 路由請求用戶信息時,授權失敗。 任何幫助將不勝感激,在此先感謝。
我得到錯誤:
Route matched with {action = "GetInfo", controller = "Accounts", page = ""}. Executing controller action with signature System.Threading.Tasks.Task`1[ProjectConker.Controllers.AccountsInfo] GetInfo() on controller ProjectConker.Controllers.AccountsController (ProjectConker).
info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]
Authorization failed.
這是發行令牌的地方。
[HttpPost("login")]
public async Task<IActionResult> Post([FromBody]LoginInfo credentials)
{
if (credentials == null)
{
return BadRequest("Invalid client request");
}
var user = await UserManager.FindByNameAsync(credentials.Username);
await SignInManager.SignInAsync(user, isPersistent: false);
var result = await SignInManager.PasswordSignInAsync(user,
credentials.Password, isPersistent: false, lockoutOnFailure: false);
if (result.Succeeded)
{
var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("**********"));
var signinCredentials = new SigningCredentials(secretKey, SecurityAlgorithms.HmacSha256);
var tokeOptions = new JwtSecurityToken(
issuer: "http://localhost:5000",
audience: "http://localhost:5000",
claims: new List<Claim>(){
new Claim("username", credentials.Username)
},
expires: DateTime.Now.AddMinutes(5),
signingCredentials: signinCredentials
);
var tokenString = new JwtSecurityTokenHandler().WriteToken(tokeOptions);
return Ok(new { Token = tokenString, UserName = user.UserName });
}
else
{
return Unauthorized();
}
}
將令牌保存到本地存儲
public Login(loginForm : ILoginForm) : Observable<ILoginForm>
{
return this.http.post<ILoginForm>(this.accountsUrl + "/login", loginForm, httpOptions)
.pipe(map<any, any>((data, index) => {
localStorage.setItem("auth_token", data.token);
this.username = data.username;
this.loggedIn = true;
console.log(data);
return data;
}));
}
獲取用戶信息
public GetAccountInfo() : Observable<any>
{
httpOptions.headers.set('Authorization', localStorage.getItem('auth_token'));
return this.http.get(this.accountsUrl + "/info", httpOptions);
}
返回用戶信息,但此處授權失敗
[HttpGet]
[Route("info")]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public async Task<AccountsInfo> GetInfo()
{
var usernameClaim = User.Claims.SingleOrDefault(c => c.Type == "username");
Console.WriteLine(usernameClaim.Value, ConsoleColor.Red);
var user = await UserManager.FindByNameAsync(usernameClaim.Value);
return new AccountsInfo{ DisplayName = user.UserName };
}
我的啟動.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = "http://localhost:5000",
ValidAudience = "http://localhost:5000",
IssuerSigningKey = new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes("superSecretKey@345"))
};
});
//services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
// In production, the Angular files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/dist";
});
services.AddHttpClient();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddCors(options => options.AddPolicy("CorsPolicy",
builder =>
{
builder.AllowAnyMethod().AllowAnyHeader()
.WithOrigins("*")
.AllowCredentials();
}));
services.AddSignalR();
services.AddEntityFrameworkSqlServer();
services.AddDbContext<ConkerDbContext>(
options => options.UseQueryTrackingBehavior(QueryTrackingBehavior.TrackAll));
services.AddIdentity<IdentityUser, IdentityRole>().AddEntityFrameworkStores<ConkerDbContext>();
services.AddScoped<SearchEngine>();
services.AddTransient<RoadmapService>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
// 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.UseHttpsRedirection();
app.UseStaticFiles();
app.UseSpaStaticFiles();
app.UseAuthentication();
app.UseSignalR(routes =>
{
routes.MapHub<ChatHub>("/api/chat");
});
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller}/{action=Index}/{id?}");
});
app.UseSpa(spa =>
{
// To learn more about options for serving an Angular SPA from ASP.NET Core,
// see https://go.microsoft.com/fwlink/?linkid=864501
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseAngularCliServer(npmScript: "start");
}
});
}
在 ASP.NET 核心令牌認證的 HTTP 請求中添加授權 header 的默認方法是在令牌之前添加Bearer 。 所以代碼應該是這樣的-
httpOptions.headers.set('Authorization', "Bearer " + localStorage.getItem('auth_token'));
您可以覆蓋默認行為以消除對Bearer的需要。 請閱讀以下帖子以幫助了解在令牌之前使用不記名的原因。 https://www.quora.com/Why-is-Bearer-required-before-the-token-in-Authorization-header-in-a-HTTP-request
也試試這個,
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(claims),
Expires = DateTime.Now.AddDays(1),
SigningCredentials = creds,
IssuedAt = DateTime.Now,
NotBefore = DateTime.Now
};
var tokenHandler = new JwtSecurityTokenHandler();
var token = tokenHandler.CreateToken(tokenDescriptor);
我的意思是不是創建一個新的 JWTSecurityToken,而是創建一個 SecuritTokenDescriptor,而不是使用 function WriteToken,而是使用 CreateToken。 我以這種方式使用了 JWT 並且它有效。
由於 Angular 的 HttpHeaders 是不可變的,你不能只使用httpOptions.headers.set('Authorization', localStorage.getItem('auth_token'));
, 因為它對原來的 object 沒有影響。
首先是 header 無效,使用 Ashique 提供的 Bearer 方法,您的 GetAccountInfo 調用將如下所示:
public GetAccountInfo() : Observable<any> {
const headers = new HttpHeaders({'Authorization': 'Bearer ' + localStorage.getItem('auth_token')});
return this.http.get(this.accountsUrl + "/info", {headers});
}
這里我假設您沒有設置其他 HttpOptions,所以我只是將 header 傳遞給 HttpClient。 以這種方式嘗試,讓我們知道它是否仍然無法正常工作。
在您創建令牌的登錄端點中,您正在使用密鑰“**********”,在設置 class 中,您正在使用密鑰“superSecretKey@345”,這是問題所在,身份驗證中間件是嘗試驗證傳入的 JWT 令牌,其密鑰與用於頒發令牌的密鑰不同,您必須使用相同的密鑰進行頒發和驗證,還將密鑰放在“appsettings”等其他地方以避免這種沖突
var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("**********"));
IssuerSigningKey = new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes("superSecretKey@345"))
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.