【问题标题】:JWT Authorization in .NET Core -- 401 Error.NET Core 中的 JWT 授权——401 错误
【发布时间】:2019-01-04 18:19:17
【问题描述】:

我正在尝试在简单的 UI 和 Web API 之间实现 JWT 身份验证。两者都是 .NET Core 2.0,我使用 Ajax 调用 API 函数。我可以毫无问题地登录,并将 Bearer 令牌传回给我;但是,当我使用 Authorize 装饰 SaveProduct 方法,使用 Ajax 调用它并传递令牌时,它返回 401 Unauthorized。一旦我删除授权,它就可以正常工作。我已经工作了好几天来弄清楚我缺少什么,并创建了我的应用程序的几次迭代,看看这是否会有所帮助,但一直无法弄清楚。我在网上搜索并尝试了许多建议,但仍然无济于事。

如果您有任何见解,我将不胜感激。提前致谢!

这是我的代码:

WEB API -- 启动

using System.Text;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;

namespace SportsStoreAngAPI
{
    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.AddCors(options => 
            {
                options.AddPolicy("AllowAllOrigins",
                    builder => builder.AllowAnyOrigin()
                            .AllowAnyHeader()
                            .AllowAnyMethod()
                            .AllowCredentials()
                    .Build());
            });    
            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                .AddJwtBearer(options =>
                {
                    options.TokenValidationParameters = new TokenValidationParameters
                    {
                        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("superdooperultrasafeKey#999")),
                        RequireSignedTokens = false,
                        ValidateIssuer = true,
                        ValidateAudience = true,
                        ValidateLifetime = true,
                        ValidateIssuerSigningKey = true,
                        ValidIssuer = "http://localhost:3700",
                        ValidAudience = "http://localhost:3700"
                    };
                });

            services.AddMvc();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            app.UseCors("AllowAllOrigins");
            app.UseStatusCodePages();
            app.UseDeveloperExceptionPage();
            app.UseStaticFiles();
            app.UseAuthentication();
            app.UseMvc();
        }
    }
}

WEB API -- 登录控制器

using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using SportsStoreAngAPI.Models;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SportsStoreAngAPI.Controllers
{
    [Route("[controller]")]
    public class LoginController : Controller
    {
        [HttpPost]
        public JsonResult Login([FromBody] LoginModel user)
        {
            LoginReturnModel l = new LoginReturnModel();

            if (user == null)
            {
                l.Success = false;
                l.Token = null;
            }

            if (user.Name == "admin" && user.Password == "secret")
            {
                var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("superSecretKey@345"));
                var signinCredentials = new SigningCredentials(secretKey, SecurityAlgorithms.HmacSha256);

                var tokenOptions = new JwtSecurityToken(
                    //issuer: "http://localhost:3700",
                    //audience: "http://localhost:3700",
                    //claims: new List<Claim>(),
                    expires: DateTime.Now.AddDays(5),
                    signingCredentials: signinCredentials
                );

                var tokenString = new JwtSecurityTokenHandler().WriteToken(tokenOptions);
                l.Success = true;
                l.Token = tokenString;
            }
            else
            {
                l.Success = false;
                l.Token = null;
            }

            JsonResult jR = new JsonResult(l);
            return jR;
        }
    }
}

WEB API - 产品控制器

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using SportsStoreAngAPI.Models;
using System.Collections.Generic;

namespace SportsStoreAngAPI.Controllers
{
    [Produces("application/json")]
    [Route("[controller]")]
    public class ProductsController : Controller
    {
        [HttpGet]
        public IEnumerable<Product> GetProducts()
        {
            List<Product> p = new List<Product>();

            return p;
        }

        [HttpPost, Authorize]
        public Product SaveProduct([FromBody]Product p)
        {
            return p;
        }
    }
}

前端用户界面

@{
    ViewData["Title"] = "Home Page";
}

<button class="btn btn-primary" type="button" onclick="loginAPI()">Login</button>

<div name="puthere" id="puthere"></div>

<button class="btn btn-primary" type="button" onclick="postNewRecord()">Post New Record</button>

<div name="puthere2" id="puthere2"></div>

<script>

    $(document).ready(function () {

    });
    var token = '';

    var loginAPI = function () {
        var myData =
            {
                Name: 'admin',
                Password: 'secret'
            };

        var myDataString = JSON.stringify(myData);

        $.ajax({
            type: 'POST',
            url: 'http://localhost:3700/login',
            contentType: 'application/json;charset=utf-8',
            dataType: 'json',
            data: myDataString,
            success: function (results) {
                $('#puthere').empty();
                var html = '';
                $.each(results, function (index, value) {
                    html = html + '<p>' + index + ' : ' + value + '</p>';
                    if (index == 'token') {
                        token = value;
                    };
                });
                $('#puthere').append(html);
            },
            error: function (xhr, textStatus, error) {
                alert(Error);
                alert(xhr.statusText);
                alert(textStatus);
                alert(error);
            }
        });
    };

    var postNewRecord = function () {
        var myData =
            {
                Id: '0',
                Name: 'Soccer Ball',
                Category: 'Sports',
                Description: 'Round ball for playing the beautiful game',
                Price: '13.75'
            };

        var myDataString = JSON.stringify(myData);

        $.ajax({
            type: 'POST',
            url: 'http://localhost:3700/products',
            contentType: 'application/json;charset=utf-8',
            dataType: 'json',
            data: myDataString,
            beforeSend: function (xhr) {
                xhr.setRequestHeader('Authorization', token)
            },
            success: function() {
                alert('Saved successfully!');
            },
            error: function () {
                alert('Something went very wrong!');
            }
        });
    };
</script>

【问题讨论】:

    标签: asp.net-mvc asp.net-core jwt asp.net-ajax


    【解决方案1】:

    编辑:在您的 Startup-Class 中,您定义了一个与生成令牌时使用的密钥不同的密钥。它们也必须相同。我建议您阅读一些有关 JWT 及其工作原理的信息 here

    所以我注意到的第一件事是您从后端生成的令牌中删除了颁发者。您必须定义它们,因为您还在 Startup-Class 中设置了它们。

    其次,您的 ajax 请求标头必须这样设置:

    xhr.setRequestHeader('Authorization', 'Bearer ' + token)
    

    您必须在 headers-value 中定义授权类型。

    【讨论】:

    • 我将 Bearer 添加到 setRequestHeader 调用中,并从后端的发行者那里删除了评论。仍然在响应头中得到这个:WWW-Authenticate: Bearer error="invalid_token", error_description="签名无效"
    • 我更新了答案。您应该确保您配置的令牌必须提供,否则身份验证将失败。
    • 成功了!我在一个地方改变了它,但在另一个地方没有改变。我还需要取消注释观众才能使其正常工作。感谢您的帮助!
    • 很高兴它有帮助。
    猜你喜欢
    • 1970-01-01
    • 2017-10-18
    • 2019-08-05
    • 1970-01-01
    • 2019-06-05
    • 2020-03-28
    • 2016-12-14
    • 2020-07-02
    • 2020-03-04
    相关资源
    最近更新 更多