即使包含了承载令牌,Netcore API也会返回401

时间:2018-07-27 13:22:59

标签: c# asp.net-core

我想保护我的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

2 个答案:

答案 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)

在使用MVC之前,您应该先使用身份验证:

app.UseAuthentication();
app.UseMvc();

HTTP管道按顺序执行,这里是文档的link,以获取更多信息