1
votes

L'autorisation JWT .NET core a échoué?

J'essaie de faire fonctionner JWT ici, le jeton est reçu avec succès du côté de mon client après la connexion, mais lorsque je demande des informations utilisateur sur la route / info, l'autorisation échoue. Toute aide serait très appréciée, merci d'avance.

J'obtiens l'erreur:

    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");
                }
            });


        }

C'est ici que le jeton est émis.

    [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 };
     }

Enregistrer le jeton dans le stockage local

    public GetAccountInfo() : Observable<any>
    {
        httpOptions.headers.set('Authorization', localStorage.getItem('auth_token'));
        return this.http.get(this.accountsUrl + "/info", httpOptions);
    }

Obtient les informations utilisateur

    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;
        }));
    }

renvoie les informations utilisateur, mais l'autorisation échoue ici

        [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();
            }
        }

Mon startup.cs

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.


0 commentaires

3 Réponses :


2
votes

La méthode par défaut pour ajouter un en-tête d'autorisation dans la requête HTTP pour l'authentification par jeton ASP.NET core consiste à ajouter Bearer avant le jeton. Le code devrait donc ressembler à ceci:

            var tokenDescriptor = new SecurityTokenDescriptor
            {
                Subject = new ClaimsIdentity(claims),
                Expires = DateTime.Now.AddDays(1),
                SigningCredentials = creds,
                IssuedAt = DateTime.Now,
                NotBefore = DateTime.Now
            };

            var tokenHandler = new JwtSecurityTokenHandler();

            var token = tokenHandler.CreateToken(tokenDescriptor);

Vous pouvez remplacer le comportement par défaut pour supprimer le besoin de Bearer . Veuillez lire l'article ci-dessous pour vous aider à comprendre la raison de l'utilisation du porteur avant le jeton. https://www.quora.com/Why-is-Bearer-required-before-the-token-in-Authorization-header-in-a-HTTP-request

Essayez également ceci,

httpOptions.headers.set('Authorization', "Bearer " + localStorage.getItem('auth_token'));

Au lieu de créer un nouveau JWTSecurityToken, créez un SecuritTokenDescriptor, au lieu d'utiliser la fonction WriteToken, utilisez CreateToken. J'ai utilisé JWT de cette manière et cela a fonctionné.


1 commentaires

J'obtiens toujours la même erreur non autorisée après cela. Mais bon de savoir que cela doit être là.



2
votes

Les HttpHeaders d'Angular étant immuables , vous ne pouvez pas simplement utiliser httpOptions.headers.set ('Authorization', localStorage.getItem ('auth_token')); , car cela n'aurait aucun effet sur l'objet d'origine.

La première chose est que l'en-tête n'est pas valide, utilisez le Bearer méthode fournie par Ashique, alors votre appel GetAccountInfo ressemblerait à ceci:

public GetAccountInfo() : Observable<any> {
    const headers = new HttpHeaders({'Authorization': 'Bearer ' + localStorage.getItem('auth_token')});
    return this.http.get(this.accountsUrl + "/info", {headers});
}

Ici, j'ai supposé que vous n'avez pas d'autres HttpOptions définies, donc je ne fais que passer l'en-tête au HttpClient. Essayez-le de cette façon et faites-nous savoir si cela ne fonctionne toujours pas.


1 commentaires

OOOOH, MERCI C'ÉTAIT CELA



1
votes

Dans le point de terminaison de connexion où vous créez le jeton que vous utilisez la clé "**********" et dans la classe Setup vous utilisez la clé "superSecretKey @ 345", c'est le problème, le le middleware d'authentification tente de valider les jetons JWT entrants avec une clé différente de la clé utilisée pour émettre le jeton, vous devez utiliser la même clé à la fois pour l'émission et la validation, placez également la clé ailleurs comme "appsettings" pour éviter ce conflit

var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("**********"));
IssuerSigningKey = new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes("superSecretKey@345"))


1 commentaires

Mon mal pour l'incohérence, mais j'ai oublié d'astériser le second pour la confidentialité.