C# JWT身份验证,忽略Authorize属性中定义的角色
在尝试使用JWT作为默认身份验证方案来实现基于角色的身份验证时,我遇到了一种情况,即忽略了C# JWT身份验证,忽略Authorize属性中定义的角色,c#,asp.net-core,jwt,authorization,asp.net-identity,C#,Asp.net Core,Jwt,Authorization,Asp.net Identity,在尝试使用JWT作为默认身份验证方案来实现基于角色的身份验证时,我遇到了一种情况,即忽略了Authorize属性中定义的角色,允许任何请求(带有有效令牌)通过,即使不在这些角色中,(有趣的是,在相同的Authorize属性中定义了自定义需求的其他策略工作正常) 阅读时他提到 这里有一个很好的发现:ASP.NET Core中的JWT中间件知道如何解释JWT负载中的“角色”声明,并将适当的声明添加到声明实体。这使得对角色使用[Authorize]属性非常容易 以及: 这是一个非常有趣的地方,当你考虑
Authorize
属性中定义的角色,允许任何请求(带有有效令牌)通过,即使不在这些角色中,(有趣的是,在相同的Authorize
属性中定义了自定义需求的其他策略工作正常)
阅读时他提到
这里有一个很好的发现:ASP.NET Core中的JWT中间件知道如何解释JWT负载中的“角色”声明,并将适当的声明添加到声明实体
。这使得对角色使用[Authorize]
属性非常容易
以及:
<>这是一个非常有趣的地方,当你考虑把角色传递给<代码> [授权] < /> >实际上会查看是否有一个具有你所授权的角色的值的类型声明。这意味着我可以简单地添加<代码> [授权(角色=“admin”)]。到任何API方法,这将确保只有有效负载包含声明“roles”(包含角色数组中的Admin值)的JWT才会被授权使用该API方法
这仍然成立吗?(这篇文章已经有好几年了)我做错什么了吗 启动(配置服务)
public void配置服务(IServiceCollection服务)
{
字符串defaultConnection=Configuration.GetConnectionString(“默认”);
services.AddDbContext(options=>options.UseSqlServer(defaultConnection.UseQueryTrackingBehavior(QueryTrackingBehavior.TrackAll));
服务.额外性()
.AddEntityFrameworkStores()
.AddDefaultTokenProviders();
services.AddAuthorization(o=>o.AddPolicy(Policy.IsInTenant,x=>x.AddRequirements(new-isintenanterrequirement()));
services.AddAuthentication(x=>
{
x、 DefaultAuthenticateScheme=JwtBearerDefaults.AuthenticationScheme;
x、 DefaultChallengeScheme=JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(x=>
{
x、 SaveToken=true;
x、 TokenValidationParameters=新的TokenValidationParameters
{
IssuerSigningKey=新对称性安全密钥(密钥),
validateisuer=true,
ValidateAudience=true,
ValidAudience=“某个主机…”,
ValidIssuer=“somehost…”,
};
});
}
启动(配置)
public void配置(IApplicationBuilder应用程序,IWebHostEnvironment)
{
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(x=>x.MapController());
}
控制器:
[ApiController]
[Authorize(Roles=“some_random_string_which_not_registered_anywhere”)]/以下是关于如何使用JWT基于角色的身份验证的完整工作演示:
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters()
{
ValidIssuer = Configuration["Jwt:JwtIssuer"],
ValidAudience = Configuration["Jwt:JwtIssuer"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:JwtKey"])),
ValidateIssuer = true,
ValidateAudience = true,
ValidateIssuerSigningKey = true,
};
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
endpoints.MapControllers();
});
}
在appSettings.json中存储发行人
、受众
和签名密钥
:
"jwt": {
"JwtKey": "YourJwtKey",
"JwtIssuer": "YourJwtIssuer"
}
生成令牌:
[Route("api/[Controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
private IConfiguration _config;
public ValuesController(IConfiguration config)
{
_config = config;
}
[Route("GenerateToken")]
public async Task<IActionResult> GenerateToken()
{
var claims = new List<Claim>
{
new Claim(ClaimTypes.Role, "Admin")
};
var token = new JwtSecurityToken(_config["Jwt:JwtIssuer"],
_config["Jwt:JwtIssuer"],
claims: claims,
expires: DateTime.Now.AddDays(5),
signingCredentials: new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:JwtKey"])),
SecurityAlgorithms.HmacSha256));
var data = new JwtSecurityTokenHandler().WriteToken(token);
return Ok(new { data });
}
}
[路由(“api/[控制器]”)]
[ApiController]
公共类值控制器:控制器库
{
私有IConfiguration\u config;
公共价值控制器(IConfiguration配置)
{
_config=config;
}
[路线(“GenerateToken”)]
公共异步任务GenerateToken()
{
var索赔=新列表
{
新索赔(ClaimTypes.Role,“Admin”)
};
var-token=新的JwtSecurityToken(_-config[“Jwt:JwtIssuer”],
_配置[“Jwt:JwtIssuer”],
索赔:索赔,
过期日期:DateTime.Now.AddDays(5),
signingCredentials:new signingCredentials(新的SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config[“Jwt:JwtKey”])),
SecurityAlgorithms.HmacSha256);
var data=new JwtSecurityTokenHandler().WriteToken(令牌);
返回Ok(新的{data});
}
}
试验方法:
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
[Authorize(Roles = "admin")]
[HttpGet]
public async Task<IActionResult> Get()
{
return Ok();
}
[Authorize(Roles = "Admin")]
[HttpGet("GetAdmin")]
public async Task<IActionResult> GetAdmin()
{
return Ok();
}
}
[ApiController]
[路线(“[控制器]”)]
公共类WeatherForecastController:ControllerBase
{
[授权(Roles=“admin”)]
[HttpGet]
公共异步任务Get()
{
返回Ok();
}
[授权(Roles=“Admin”)]
[HttpGet(“GetAdmin”)]
公共异步任务GetAdmin()
{
返回Ok();
}
}
结果:
参考:
以下是关于如何使用JWT基于角色的身份验证的完整演示:
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters()
{
ValidIssuer = Configuration["Jwt:JwtIssuer"],
ValidAudience = Configuration["Jwt:JwtIssuer"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:JwtKey"])),
ValidateIssuer = true,
ValidateAudience = true,
ValidateIssuerSigningKey = true,
};
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
endpoints.MapControllers();
});
}
在appSettings.json中存储发行人
、受众
和签名密钥
:
"jwt": {
"JwtKey": "YourJwtKey",
"JwtIssuer": "YourJwtIssuer"
}
生成令牌:
[Route("api/[Controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
private IConfiguration _config;
public ValuesController(IConfiguration config)
{
_config = config;
}
[Route("GenerateToken")]
public async Task<IActionResult> GenerateToken()
{
var claims = new List<Claim>
{
new Claim(ClaimTypes.Role, "Admin")
};
var token = new JwtSecurityToken(_config["Jwt:JwtIssuer"],
_config["Jwt:JwtIssuer"],
claims: claims,
expires: DateTime.Now.AddDays(5),
signingCredentials: new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:JwtKey"])),
SecurityAlgorithms.HmacSha256));
var data = new JwtSecurityTokenHandler().WriteToken(token);
return Ok(new { data });
}
}
[路由(“api/[控制器]”)]
[ApiController]
公共类值控制器:控制器库
{
私有IConfiguration\u config;
公共价值控制器(IConfiguration配置)
{
_config=config;
}
[路线(“GenerateToken”)]
公共异步任务GenerateToken()
{
var索赔=新列表
{
新索赔(ClaimTypes.Role,“Admin”)
};
var-token=新的JwtSecurityToken(_-config[“Jwt:JwtIssuer”],
_配置[“Jwt:JwtIssuer”],
索赔:索赔,
过期日期:DateTime.Now.AddDays(5),
signingCredentials:new signingCredentials(新的SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config[“Jwt:JwtKey”])),
SecurityAlgorithms.HmacSha256);
var data=new JwtSecurityTokenHandler().WriteToken(令牌);
返回Ok(新的{data});
}
}
试验方法:
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
[Authorize(Roles = "admin")]
[HttpGet]
public async Task<IActionResult> Get()
{
return Ok();
}
[Authorize(Roles = "Admin")]
[HttpGet("GetAdmin")]
public async Task<IActionResult> GetAdmin()
{
return Ok();
}
}
[ApiController]
[路线(“[控制器]”)]
公共W类
public class IsInTenantRequirement : IAuthorizationRequirement { }
public class IsInTenantAuthorizationHandler : AuthorizationHandler<IsInTenantRequirement>
{
private readonly RouteData _routeData;
public IsInTenantAuthorizationHandler(IHttpContextAccessor httpContextAccessor)
{
_routeData = httpContextAccessor.HttpContext.GetRouteData();
}
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, IsInTenantRequirement requirement)
{
var tenantIdFromRequest = _routeData.Values["tenantId"]?.ToString();
var tenantId = context.User.FindFirstValue(AppClaim.TenantId);
if (tenantIdFromRequest == tenantId)
{
context.Succeed(requirement);
}
context.Succeed(requirement);
return Task.CompletedTask;
}
}