Skip to main content
 首页 » 编程设计

c#之Asp.Net 核心 WebApi : Authorize attribute Error 403

2024年01月18日27落叶

我在 Asp.Net Core WebApi 项目中工作并创建了一个角色 “admin” 并将其添加到我的用户。但是,如果我以管理员身份登录,第一个方法将返回 “这是管理员!”,但第二个方法将返回错误 403 Forbidden。

如果我从 Authorize 属性中删除 Roles 参数,一切都会正常进行。我不明白为什么我不能访问第二种方法,因为我的用户具有管理员角色。

// Host/api/roles/getroles 
        [Authorize] 
        [HttpGet] 
        public async Task<IEnumerable<string>> GetRoles() 
        { 
            var user = await _userManager.GetUserAsync(User); 
 
            bool isAdmin = await _userManager.IsInRoleAsync(user, Roles.AdminRole);                
            if (isAdmin) 
                return new[] {"This is admin!"}; 
 
            return await _userManager.GetRolesAsync(user); 
        } 
 
 
        // ===== Admin Methods ===== 
 
        // Host/api/roles/createrole 
        [Authorize(Roles = Roles.AdminRole)] 
        [HttpPost] 
        public async Task<IActionResult> CreateRole([FromBody] CreateRoleViewModel model) 
        { 
            if (!ModelState.IsValid) 
            { 
                return BadRequest(); 
            } 
 
            var result = await _roleManager.CreateAsync(new IdentityRole(model.RoleName)); 
 
            if (!result.Succeeded) 
                return BadRequest(result); 
 
            return Ok(); 
        } 

在我发送的第二种方法的请求中:

标题: 内容类型:应用程序/json 授权:承载 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJh...

正文: RoleName = "程序员"

也许我需要在标题中添加一些内容?

Startup.cs

public class Startup 
    { 
        public IConfiguration Configuration { get; } 
 
        public Startup(IConfiguration configuration) 
        { 
            Configuration = configuration; 
        } 
 
 
        public void ConfigureServices(IServiceCollection services) 
        { 
            // ===== Add DbContext ======== 
            var connectionString = Configuration.GetConnectionString("DbConnection"); 
            services.AddDbContext<ApplicationDbContext>(options => 
                options.UseSqlServer(connectionString)); 
 
            // ===== Add Identity ======== 
            services.AddIdentity<User, IdentityRole> (opts=> { 
                opts.Password.RequiredLength = 5; 
                opts.Password.RequireNonAlphanumeric = false; 
                opts.Password.RequireLowercase = false; 
                opts.Password.RequireUppercase = false; 
                opts.Password.RequireDigit = false; 
                })  
                .AddEntityFrameworkStores<ApplicationDbContext>() 
                .AddDefaultTokenProviders(); 
 
            // ===== Add Jwt Authentication ======== 
            JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); // => remove default claims 
            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(); 
        } 
 
        // 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(); 
            } 
 
            // ===== Use Authentication ====== 
            app.UseAuthentication(); 
 
            // ===== Use MVC ===== 
            app.UseMvc(); 
        } 
    } 

创建 JWT token 方法

// ===== Token ===== 
        private async Task<object> GenerateJwtToken(IdentityUser user) 
        { 
            var claims = new List<Claim> 
            { 
                new Claim(JwtRegisteredClaimNames.Sub, user.UserName), 
                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["JwtExpireDays"])); 
 
            var token = new JwtSecurityToken( 
                _configuration["JwtIssuer"], 
                _configuration["JwtIssuer"], 
                claims, 
                expires: expires, 
                signingCredentials: creds 
            ); 
 
            return new JwtSecurityTokenHandler().WriteToken(token); 
        } 

请您参考如下方法:

我更改了我的 GenerateJwtToken() 方法以将角色添加为声明:

// Get User roles and add them to claims 
                var roles = await _userManager.GetRolesAsync(user); 
                AddRolesToClaims(claims, roles); 
 
// ===== Token ===== 
        private async Task<object> GenerateJwtToken(User user) 
        { 
            var claims = new List<Claim> 
            { 
                new Claim(JwtRegisteredClaimNames.Sub, user.UserName), 
                new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()), 
                new Claim(ClaimTypes.NameIdentifier, user.Id), 
            }; 
 
            // Get User roles and add them to claims 
            var roles = await _userManager.GetRolesAsync(user); 
            AddRolesToClaims(claims, roles); 
 
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["JwtKey"])); 
            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); 
            var expires = DateTime.Now.AddDays(Convert.ToDouble(_configuration["JwtExpireDays"])); 
 
            var token = new JwtSecurityToken( 
                _configuration["JwtIssuer"], 
                _configuration["JwtIssuer"], 
                claims, 
                expires: expires, 
                signingCredentials: creds 
            ); 
 
            return new JwtSecurityTokenHandler().WriteToken(token); 
        } 
 
 
        private void AddRolesToClaims(List<Claim> claims, IEnumerable<string> roles) 
        { 
            foreach (var role in roles) 
            { 
                var roleClaim = new Claim(ClaimTypes.Role, role); 
                claims.Add(roleClaim); 
            } 
        }