我想保护我的API端点,以便只能通过身份验证进行访问,最终导致出现此错误。我使用register方法注册用户并获得令牌。然后,我在请求标头中使用该长令牌访问受保护的区域。但是我一直在授权401错误。到底是怎么回事!
http Get http://localhost:5000/Account/Protected 'authorization:Bearer eyJhb....fx0IM'
HTTP/1.1 401 Unauthorized
Content-Length: 0
Date: Fri, 27 Jul 2018 12:36:46 GMT
Server: Kestrel
WWW-Authenticate: Bearer error="invalid_token", error_description="The token as no expiration"
我具有Account Controller
的控制器配置。现在,如果我想使用受保护的控制器添加测试api,则Register方法可以很好地工作并注册人员。我收到401错误。
namespace Lemon.Auth.Controllers
{
[Route("[controller]/[action]")]
public class AccountController : ControllerBase
{
private readonly SignInManager<IdentityUser> _signInManager;
private readonly UserManager<IdentityUser> _userManager;
private readonly IConfiguration _configuration;
public AccountController(
UserManager<IdentityUser> userManager,
SignInManager<IdentityUser> signInManager,
IConfiguration configuration
)
{
_userManager = userManager;
_signInManager = signInManager;
_configuration = configuration;
}
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)
[HttpGet]
public async Task<object> Protected()
{
return "Protected area";
}
// Handlers
[HttpPost]
public async Task<object> Login([FromBody] LoginDto model)
{
var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, false, false);
if(result.Succeeded)
{
var appUser = _userManager.Users.SingleOrDefault(r => r.Email == model.Email);
return await GenerateJwtToken(model.Email, appUser);
}
throw new ApplicationException("Invalid Login Attempt");
}
// Handler :Register:
public async Task<object> Register([FromBody] RegisterDto model)
{
var user = new IdentityUser
{
UserName = model.Email,
Email = model.Email
};
// debuggi
try
{
var result = await _userManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await _signInManager.SignInAsync(user, false);
return await GenerateJwtToken(model.Email, user);
}
}
catch (System.Exception ex)
{
Console.WriteLine(ex.ToString());
}
throw new ApplicationException("Unknown Error");
}
private async Task<object> GenerateJwtToken(string email, IdentityUser user)
{
var claims = new List<Claim>
{
new Claim(JwtRegisteredClaimNames.Sub, email),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(ClaimTypes.NameIdentifier, user.Id)
};
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["JwtKey"]));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
// var expires = DateTime.Now.AddDays(Convert.ToDouble(_configuration["JwtExpiresDays"]));
Console.WriteLine("hello");
var token = new JwtSecurityToken(
_configuration["JwtIssuer"],
_configuration["JwtIssuer"],
claims,
signingCredentials: creds
);
return new JwtSecurityTokenHandler().WriteToken(token);
}
}
}
这是我的Startup.cs
public void ConfigureServices(IServiceCollection services)
{
// Db and context
services.AddEntityFrameworkNpgsql().AddDbContext<ApplicationDbContext>(options =>
{
options.UseNpgsql(Configuration.GetConnectionString("DefaultConnection"));
}
);
// add Identity
services.AddIdentity<IdentityUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
// add jwt
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); // clear default behaviour
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(cfg =>
{
cfg.RequireHttpsMetadata = false;
cfg.SaveToken = true;
cfg.TokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = Configuration["JwtIssuer"],
ValidAudience = Configuration["JwtIssuer"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["JwtKey"])),
ClockSkew = TimeSpan.Zero // remove delay of token when expire
};
});
// add mvc
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ApplicationDbContext dbContext)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
// app.UseHttpsRedirection();
app.UseMvc();
app.UseAuthentication();
// ensure tables are created
dbContext.Database.EnsureCreated();
}
我要实现的只是保护API。我查阅了本教程https://medium.com/@ozgurgul/asp-net-core-2-0-webapi-jwt-authentication-with-identity-mysql-3698eeba6ff8
答案 0 :(得分:3)
编辑2 :我刚刚看到了您正在使用的教程。它已经做了相同的事情。您可以尝试向令牌添加到期日期吗?错误消息显示令牌没有到期。
private async Task<object> GenerateJwtToken(string email, IdentityUser user)
{
var claims = new List<Claim>
{
new Claim(JwtRegisteredClaimNames.Sub, email),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(ClaimTypes.NameIdentifier, user.Id)
};
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["JwtKey"]));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
// var expires = DateTime.Now.AddDays(Convert.ToDouble(_configuration["JwtExpiresDays"]));
Console.WriteLine("hello");
var token = new JwtSecurityToken(
_configuration["JwtIssuer"],
_configuration["JwtIssuer"],
claims,
expires: DatimeTime.UtcNow.AddHours(1), // or smth else
signingCredentials: creds
);
编辑:我的第一个答案也是造成该问题的部分原因,但目前还没有。实际的问题是services.AddIdentity<,>
添加了cookie身份验证,如here所示。如果您坚持使用asp.net-identity,则必须进行一些更改。可以找到一个示例here。
旧:您的身份验证无效,因为您在mvc之后添加了身份验证。只需翻转
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ApplicationDbContext dbContext)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
// app.UseHttpsRedirection();
app.UseAuthentication();
app.UseMvc();
// ensure tables are created
dbContext.Database.EnsureCreated();
}
答案 1 :(得分:1)