我正在尝试让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 };
     }


我的startup.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");
                }
            });


        }

最佳答案

由于Angular的HttpHeaders是immutable,您不能只使用httpOptions.headers.set('Authorization', localStorage.getItem('auth_token'));,因为它不会对原始对象产生影响。

首先是标题无效,请使用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,所以我只是将标头传递给HttpClient。尝试这种方式,让我们知道它是否仍然无法正常工作。

10-06 03:07