代码之家  ›  专栏  ›  技术社区  ›  DoubleVoid

使用ASP.NET核心Web API中的JWT授权检查IP

  •  1
  • DoubleVoid  · 技术社区  · 6 年前

    使用时是否可以检查IP地址? System.IdentityModel.Tokens.Jwt 在ASP.NET核心Web API应用程序中?

    我考虑添加一个声明,其中包含请求它的用户的IP,并以某种方式检查每个请求。通常我会用 OnActionExecuting 在ASP.NET MVC中。

    是否有基于中间件/授权的解决方案?

    我创建了这样的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索赔的可能解决方案? 也许我必须阅读这样的声明(测试代码,无空检查等):

    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;
    }
    
    1 回复  |  直到 6 年前
        1
  •  2
  •   Tseng    6 年前

    您可以通过 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"))
    })