401未经授权:WWW认证:承载

时间:2019-04-21 08:07:25

标签: asp.net-mvc jwt angular7 bearer-token

我看到过与此问题类似的话题,但是我没有运气解决它。 登录工作成功,但是当我尝试获取主页中登录用户的数据时,出现此错误401未经授权,邮递员中也显示相同的错误

我的startup.cs

 public class Startup
    {
        private string _connectionString=null;
        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)
        {
            //Inject AppSettings
            services.Configure<ApplicationSettings>(Configuration.GetSection("ApplicationSettings"));
            _connectionString = Configuration["secretConnectionstring"];

            //without this it will define for example id to Id 
            services.AddMvc()
                .SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
                .AddJsonOptions(options => {
                    var resolver = options.SerializerSettings.ContractResolver;
                    if (resolver != null)
                        (resolver as DefaultContractResolver).NamingStrategy = null;
                });

            services.AddEntityFrameworkNpgsql()
                .AddDbContext<ApiContext>(
                opt => opt.UseNpgsql(_connectionString));

            services.AddEntityFrameworkNpgsql()
                .AddDbContext<AuthentificationContext>(
                options => options.UseNpgsql(_connectionString));
            services.AddDefaultIdentity<ApplicationUser>()
                .AddEntityFrameworkStores<AuthentificationContext>();

            services.Configure<IdentityOptions>(options => {
                options.Password.RequireDigit = false;
                options.Password.RequireNonAlphanumeric = false;
                options.Password.RequireLowercase = false;
                options.Password.RequireUppercase = false;
                options.Password.RequiredLength = 4;
                });

            services.AddCors(options =>
            {
                options.AddPolicy("CorsPolicy",
                    builder => builder.AllowAnyOrigin()
                    .AllowAnyMethod()
                    .AllowAnyHeader()
                   .AllowCredentials());
            });

            // Jwt Authentification
           var key = Encoding.UTF8.GetBytes(Configuration["ApplicationSettings:JWT_Secret"].ToString());

            services.AddAuthentication(x =>
            {
                x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
                x.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
            }).AddJwtBearer(x=> {
                x.RequireHttpsMetadata = false;
                x.SaveToken = false;
                x.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(key),
                    ValidateIssuer = false,
                    ValidateAudience = false,
                    ClockSkew = TimeSpan.Zero
                };
            });

            services.AddTransient<dataSeed>();
            // In production, the Angular files will be served from this directory
            services.AddSpaStaticFiles(configuration =>
            {
                configuration.RootPath = "ClientApp/dist";
            });
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, dataSeed seed)
        {
            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();

            // global policy - assign here or on each controller
            app.UseCors("CorsPolicy");


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

            app.UseAuthentication();



        }
    }
}

UserprofileController

{
    [Route("api/[controller]")]
    [ApiController]
    public class UserProfileController : ControllerBase
    {
        private UserManager<ApplicationUser> _userManager;
        public UserProfileController(UserManager<ApplicationUser> userManager)
        {
            _userManager = userManager;
        }

        [HttpGet]
        [Authorize]
        //GET : /api/UserProfile
        public async Task<Object> GetUserProfile()
        {
            string userId = User.Claims.First(c => c.Type == "UserID").Value;
            var user = await _userManager.FindByIdAsync(userId);
            return new
            {
                user.fullName,
                user.Email,
                user.UserName
            };
        }
    }
}

UserServices

 headers = {
    headers: new HttpHeaders({
      'Content-Type': 'application/json',
      'Accept': 'application/json'
    })
  }
  readonly BaseUrl = 'http://localhost:53847/api';

  constructor(private fb: FormBuilder, private http: HttpClient) { }

  formModel = this.fb.group({
    UserName: ['', Validators.required],
    Email: ['', Validators.email],
    fullName: ['', Validators.required],
    Passwords: this.fb.group({
      Password: ['',[Validators.required, Validators.minLength(4)]],
      ConfirmPassword: ['', Validators.required],
    }, { validator : this.comparePasswords})


  });
  comparePasswords(fb: FormGroup) {

    let confirmPswdCtrl = fb.get('ConfirmPassword');
    //passowrdMismatch
    //confirmPswdCtrl.errors={passowrdMismatch:true}
    if (confirmPswdCtrl.errors == null || 'passowrdMismatch' in confirmPswdCtrl.errors) {
      if (fb.get('Password').value != confirmPswdCtrl.value)
        confirmPswdCtrl.setErrors({ passowrdMismatch: true });
      else
        confirmPswdCtrl.setErrors(null);

    }

  }

  register() {
    var body = {
      UserName: this.formModel.value.UserName,
      Email: this.formModel.value.Email,
      fullName: this.formModel.value.fullName,
      Password: this.formModel.value.Passwords.Password,

    };
    return this.http.post(this.BaseUrl + '/ApplicationUser/Register', body, this.headers);
  }

  login(formData) {
    return this.http.post(this.BaseUrl + '/ApplicationUser/Login', formData, this.headers);

  }
  getUserProfile() {
    var tokenHeader = new HttpHeaders({ 'Authorization': 'Bearer' + localStorage.getItem('token'), 'Content-Type': 'application/json' });
    return this.http.get(this.BaseUrl + '/UserProfile', { headers: tokenHeader });
  }
}

ApplicationUserController PostMethod

  [HttpPost]
        [Route("Login")]
        //POST : /api/ApplicationUser/Login
        public async Task<IActionResult> Login(LoginModel model)
        {
            var user = await _userManager.FindByNameAsync(model.UserName);
            if (user != null && await _userManager.CheckPasswordAsync(user, model.Password))
            {
                var tokenDescriptor = new SecurityTokenDescriptor
                {
                    Subject = new ClaimsIdentity(new Claim[]
                    {
                        new Claim("UserID",user.Id.ToString())
                    }),
                    Expires = DateTime.UtcNow.AddDays(1),
                    SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_appSettings.JWT_Secret)), SecurityAlgorithms.HmacSha256Signature)
                };
                var tokenHandler = new JwtSecurityTokenHandler();
                var securityToken = tokenHandler.CreateToken(tokenDescriptor);
                var token = tokenHandler.WriteToken(securityToken);
                return Ok(new { token });
            }
            else
                return BadRequest(new { message = "Username or password is incorrect." });
        }
    }

帮助Plz .. Thx

3 个答案:

答案 0 :(得分:1)

我看到的一个问题在这里:

var tokenHeader = new HttpHeaders({ 'Authorization': 'Bearer' + localStorage.getItem('token'), 'Content-Type': 'application/json' });

指定Bearer令牌时,您需要在Bearer和令牌本身之间留一个空格,以便结果看起来像this

Authorization: <type> <credentials>

在您的情况下,这将转换为:

Authorization: Bearer token

但是,如果您看一下上面的代码,您会看到您实际上将像这样提供它:

Authorization: Bearertoken

这是行不通的。因此,将代码更改为:

var tokenHeader = new HttpHeaders({ 'Authorization': 'Bearer ' + localStorage.getItem('token'), 'Content-Type': 'application/json' });
// ---------------------------------------------------------^ Notice I've added a space here.

答案 1 :(得分:0)

就我而言,我没有收到任何错误,并且一切似乎都可以正常工作,但是我的API每次都返回401。 在这个问题上,我的脑袋撞了很多。 我有...

[Authorize]

在我的Controller上,发现该站点正在尝试使用cookie身份验证,因此尽管我的JWT工作正常,但是缺少cookie身份验证使它失败了。 我将属性更改为...

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]

并解决了该问题,因为现在控制器会忽略Cookie身份验证,而只专注于jwt。 希望这对某人有帮助

答案 2 :(得分:0)

我发现更改语句顺序是我的问题。 Configure()要求ASP.NET Core中间件的顺序正确。

此DID不起作用,需要我向每个控制器添加[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] ...

app.UseAuthorization();
app.UseAuthentication();

这确实有效:

app.UseAuthentication();
app.UseAuthorization();