问题描述
我正在尝试将带有 JWT 的令牌身份验证添加到我的 .Net Core 2.0 应用程序中.我有一个简单的控制器,它返回用于测试的用户列表.
I'm trying to add Token Authentication with JWT to my .Net Core 2.0 app. I have a simple controller that returns a list of users for testing.
[Authorize]
[Route("api/[controller]")]
public class UsersController : Controller
{
...
[HttpGet]
[Route("api/Users/GetUsers")]
public IEnumerable<ApplicationUser> GetUsers()
{
return _userManager.Users;
}
}
我有一个用于令牌安全的 API 控制器.它有一个登录方法,它返回一个 Token 字符串结果.
I have an API Controller for Token security. It has a login method which returns a Token string result.
[HttpPost(nameof(Login))]
public async Task<IActionResult> Login([FromBody] LoginResource resource)
{
if (resource == null)
return BadRequest("Login resource must be asssigned");
var user = await _userManager.FindByEmailAsync(resource.Email);
if (user == null || (!(await _signInManager.PasswordSignInAsync(user, resource.Password, false, false)).Succeeded))
return BadRequest("Invalid credentials");
string result = GenerateToken(user.UserName, resource.Email);
// Token is created, we can sign out
await _signInManager.SignOutAsync();
return Ok(result);
}
private string GenerateToken(string username, string email)
{
var claims = new Claim[]
{
new Claim(ClaimTypes.Name, username),
new Claim(ClaimTypes.Email, email),
new Claim(JwtRegisteredClaimNames.Nbf, new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds().ToString()),
new Claim(JwtRegisteredClaimNames.Exp, new DateTimeOffset(DateTime.Now.AddDays(1)).ToUnixTimeSeconds().ToString()),
};
var token = new JwtSecurityToken(
new JwtHeader(new SigningCredentials(
new SymmetricSecurityKey(Encoding.UTF8.GetBytes("the secret that needs to be at least 16 characeters long for HmacSha256")),
SecurityAlgorithms.HmacSha256)),
new JwtPayload(claims));
return new JwtSecurityTokenHandler().WriteToken(token);
}
我有一个小型控制台应用程序,仅用于测试 API.当我尝试使用 jwt 获取用户时.我立即收到未经授权".如果我从用户控制器中删除[授权]"...成功.似乎无法识别我的标头授权,但不知道为什么.
I have a small console app just for testing the API. When I attempt to Get the Users using the jwt. I receive an immediate "unauthorized". If I remove the "[Authorize]" from the users Controller... success. It appears that my header Authorization is not recognized, but not sure why.
private static async Task<String> GetUsers(String jwt)
{
var url = "https://localhost:44300/";
var apiUrl = $"/api/Users/";
using (var client = new HttpClient() { BaseAddress = new Uri(url) })
{
client.BaseAddress = new Uri(url);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {jwt}");
using (var response = await client.GetAsync(apiUrl))
{
if (response.StatusCode == System.Net.HttpStatusCode.OK)
return await response.Content.ReadAsStringAsync();
else return null;
}
}
}
我的尝试基于文章这里 ... 其中一些可能有点过时.
I'm basing my attempts on the article here ... some of which might be slightly out of date.
更新 - Startup.cs 的摘录
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = "Jwt";
options.DefaultChallengeScheme = "Jwt";
}).AddJwtBearer("Jwt", options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = false,
//ValidAudience = "the audience you want to validate",
ValidateIssuer = false,
//ValidIssuer = "the isser you want to validate",
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("the secret that needs to be at least 16 characeters long for HmacSha256")),
ValidateLifetime = true, //validate the expiration and not before values in the token
ClockSkew = TimeSpan.FromMinutes(5) //5 minute tolerance for the expiration date
};
});
配置...
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseBrowserLink();
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseAuthentication();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
//app.UseJwtBearerAuthentication(
// new Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerOptions
// );
}
解决方案:
这一行正在转义令牌,因此在下一个请求中传递时导致它无效:
This line was escaping the token therefore causing it to be invalid when passed in the next request:
var result = await response.Content.ReadAsStringAsync();
替换为:
var result = await response.Content.ReadAsAsync<string>();
注意:要使用这种 ext 方法,我必须安装包 Microsoft.AspNet.WebApi.Client"
Note: To use this ext method I had to "install-package Microsoft.AspNet.WebApi.Client"
推荐答案
我在我的一个项目中使用了 JWT 身份验证.我想展示我的实现,也许这会对你有所帮助.但是你可能忘记在启动类的 configure 方法中添加 UseAuthentication(); .
I used JWT authentication in my one of project. I would like to show my implementation, maybe this will help you. But probably you forget to add UseAuthentication(); into configure method in startup class.
startup.cs
public void Configure(IApplicationBuilder app)
{
app.UseAuthentication();
app.UseMvc();
}
public void ConfigureServices(IServiceCollection services)
{
var appSettings = Configuration.GetSection("AppSettings");
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}
)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = true,
ValidAudience = appSettings["JwtAudience"],
ValidateIssuer = true,
ValidIssuer = appSettings["JwtIssuer"],
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(appSettings["JwtSigningKey"]))
};
});
}
generateToken 方法
private string GenerateToken(string email)
{
SecurityKey securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_appSettings.Value.JwtSigningKey));
var token = new JwtSecurityToken(
issuer: _appSettings.Value.JwtIssuer,
audience: _appSettings.Value.JwtAudience,
claims: new[]
{
new Claim(JwtRegisteredClaimNames.UniqueName, email),
new Claim(JwtRegisteredClaimNames.Email, email),
new Claim(JwtRegisteredClaimNames.NameId, Guid.NewGuid().ToString())
},
expires: DateTime.Now.AddMinutes(_appSettings.Value.JwtExpireMinute),
signingCredentials: new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256)
);
return new JwtSecurityTokenHandler().WriteToken(token);
}
这篇关于带有 JWT 的 Core 2.0 API Auth 返回未经授权的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!