在ASP.NET核心Web Api应用程序中使用System.IdentityModel.Tokens.Jwt
时是否可以检查IP地址?
我考虑过添加一个包含请求用户IP的Claim,并针对每个请求以某种方式对其进行检查。通常,我会在ASP.NET MVC中使用OnActionExecuting
。
是否存在基于中间件/授权的解决方案?
我这样创建我的Jwt令牌声明:
private IEnumerable<Claim> getStandardClaims(IdentityUser user)
{
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, user.UserName),
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
new Claim(JwtRegisteredClaimNames.Sub, user.UserName),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim("ipaddress", HttpContext.Connection.RemoteIpAddress.ToString())
};
return claims;
}
这是JWT数据的样子:
{
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name": "username",
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier": "5a6b3eb8-ed7f-48c6-b10c-a279ffd4f7c8",
"sub": "username",
"jti": "44c95b53-bfba-4f33-b4c3-834127605432",
"ipaddress": "::1",
"exp": 1542707081,
"iss": "https://localhost:5001/",
"aud": "https://localhost:5001/"
}
编辑:JWT索赔的可能解决方案? 也许我必须像这样阅读声明(测试代码,没有null检查等):
var auth = HttpContext.Request.Headers.FirstOrDefault(x => x.Key == "Authorization");
string token = auth.Value[0].Split(' ')[1];
JwtTokenService<RefreshToken, string> jwtService = new JwtTokenService<RefreshToken, string>(null);
var principal = jwtService.GetPrincipalFromExpiredToken(token, _config["Jwt:Key"]);
Claim ipClaim = principal.FindFirst(claim => claim.Type == "ipaddress");
这是GetPrincipalFromExpiredToken方法:
public ClaimsPrincipal GetPrincipalFromExpiredToken(string token, string securityKey)
{
var tokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = false,
ValidateIssuer = false,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(securityKey)),
ValidateLifetime = false
};
var tokenHandler = new JwtSecurityTokenHandler();
SecurityToken securityToken;
var principal = tokenHandler.ValidateToken(token, tokenValidationParameters, out securityToken);
var jwtSecurityToken = securityToken as JwtSecurityToken;
if (jwtSecurityToken == null || !jwtSecurityToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256, StringComparison.InvariantCultureIgnoreCase))
throw new SecurityTokenException("Invalid token");
return principal;
}
答案 0 :(得分:2)
您可以通过Policy-based authorization来执行此操作(以及所有其他授权操作)。
public class IpCheckRequirement : IAuthorizationRequirement
{
public bool IpClaimRequired { get; set; } = true;
}
public class IpCheckHandler : AuthorizationHandler<IpCheckRequirement>
{
public IpCheckHandler(IHttpContextAccessor httpContextAccessor)
{
HttpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor));
}
private IHttpContextAccessor HttpContextAccessor { get; }
private HttpContext HttpContext => HttpContextAccessor.HttpContext;
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, IpCheckRequirement requirement)
{
Claim ipClaim = context.User.FindFirst(claim => claim.Type == "ipaddress");
// No claim existing set and and its configured as optional so skip the check
if(ipClaim == null && !requirement.IpClaimRequired)
{
// Optional claims (IsClaimRequired=false and no "ipaddress" in the claims principal) won't call context.Fail()
// This allows next Handle to succeed. If we call Fail() the access will be denied, even if handlers
// evaluated after this one do succeed
return Task.CompletedTask;
}
if (ipClaim.Value = HttpContext.Connection.RemoteIpAddress?.ToString())
{
context.Succeed(requirement);
}
else
{
// Only call fail, to guarantee a failure, even if further handlers may succeed
context.Fail();
}
return Task.CompletedTask;
}
}
然后添加
services.AddSingleton<IAuthorizationHandler, IpCheckHandler>();
services.AddAuthorization(options =>
{
options.AddPolicy("SameIpPolicy",
policy => policy.Requirements.Add(new IpCheckRequirement { IpClaimRequired = true }));
});
您的ConfigureServices
方法。
现在,您可以使用[Authroize(Policy = "SameIpPolicy")]
注释要对其应用控制器的控制器或添加全局策略:
services.AddMvc(options =>
{
options.Filters.Add(new AuthorizeFilter("SameIpPolicy"))
})
答案 1 :(得分:0)
我通过在每个控制器上应用[Authorize(Policy =“ SameIpPolicy”)]使其与@Tseng解决方案配合使用,非常感谢! 只是为了纠正一个错字错误:
缺少半冒号:
services.AddMvc(options =>
{
options.Filters.Add(new AuthorizeFilter("SameIpPolicy"));
})