使用 JWT 和密钥来处理单点登录

问题描述 投票:0回答:1

我有一个正在运行的会员专用网站,可以通过登录等方式正常工作。 我现在需要支持单点登录,我将在 JWT 令牌中接收配置文件的用户名,然后让用户登录。 将发送此请求的外部系统除了用户名之外不知道任何其他信息 - 因此密码不会在令牌中共享,也不可能。

JWT 已被选为实现此目的的首选方法。我们将使用密钥来交换信息,密钥当然只有发送者和接收者知道。

我正在寻找一个简单的示例,说明在发送端和接收端如何从代码角度来看。 接收端将是一个 WebAPI 端点,它将处理登录,然后在登录成功时重定向到会员专用网站的首页。

它是用C#开发的。

c# asp.net authentication jwt
1个回答
3
投票

基本技巧

  • 通常,用户/密码会被交换为新的 JWT

  • JWT 不应存储任何敏感信息,例如密码。像微软这样的一些公司存储的不是合理的值,而是大量的信息https://gist.github.com/jrichardsz/6512f9b2b4c38620bf00e24c71b6cf2d

  • 对于企业来说,加解密过程不应该在微服务层执行。它应该由另一个服务器执行,例如:Auth0、okta、Keycloack 等。

  • 您的微服务仅接收令牌并将其发送到安全平台。做到这一点的最佳方法是使用任何语言的中间件。这是为了c#

  • 安全平台以客户端(在您的情况下为 c#)理解的语法返回包含数据的响应,该语法可以理解令牌是否合法、有效、未过期、用户存在、允许用户执行操作等。我在某些情况下使用了它实现中我说:“允许用户执行此操作,这是其用户名”

    端点:

    acme-security.com/v1/oauth2/token/validate

    要求:

    eyJ0eXAiOiJKV1Qi...

    回复:

    {
    "isAllowed": true,
    "subject": "[email protected]"
    }
    
  • 您也可以使用 api 网关来完成此操作

  • 在更真实的场景中,我们需要的不仅仅是简单的 jwt 验证。我们需要确保允许用户 admin/guest 执行特定端点。我们不希望员工直接调用支付端点来设置自己的工资:/

  • 如果您要实现自己的安全平台,请遵循 oauth2 规范

  • Jwt 应作为授权标头发送

  • 重要:如果您要实现自己的 jwt 生成和验证,请使用 ENV 变量来隐藏它的秘密并在生产环境中尽可能地保护它

JWT 使用 c# netcore 5 进行处理

如果理解了前面的步骤,您只需要使用以下方法之一:

  • 使用一些 IAM 或安全平台,如 auth0、okta、keycloack 等
  • 一个简单的 c# web/microservice/api(也充当安全平台),用于接收令牌并在用户允许的情况下返回
  • 目标微服务内部验证的类

智威汤逊一代

public string GenerateToken(User user)
{
    // generate token that is valid for 7 days
    var tokenHandler = new JwtSecurityTokenHandler();
    var key = Encoding.ASCII.GetBytes(SUPER_SECRET_KEY);
    var tokenDescriptor = new SecurityTokenDescriptor
    {
        Subject = new ClaimsIdentity(new[] { new Claim("id", user.Id.ToString()) }),
        Expires = DateTime.UtcNow.AddDays(7),
        SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
    };
    var token = tokenHandler.CreateToken(tokenDescriptor);
    return tokenHandler.WriteToken(token);
}

JWT 解码或验证

public int? ValidateToken(string token)
{
    if (token == null) 
        return null;

    var tokenHandler = new JwtSecurityTokenHandler();
    var key = Encoding.ASCII.GetBytes(SUPER_SECRET_KEY);
    try
    {
        tokenHandler.ValidateToken(token, new TokenValidationParameters
        {
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = new SymmetricSecurityKey(key),
            ValidateIssuer = false,
            ValidateAudience = false,
            // set clockskew to zero so tokens expire exactly at token expiration time (instead of 5 minutes later)
            ClockSkew = TimeSpan.Zero
        }, out SecurityToken validatedToken);

        var jwtToken = (JwtSecurityToken)validatedToken;
        var userId = int.Parse(jwtToken.Claims.First(x => x.Type == "id").Value);

        // return user id from JWT token if validation successful
        return userId;
    }
    catch
    {
        // return null if validation fails
        return null;
    }
}

来源:https://jasonwatmore.com/post/2021/06/02/net-5-create-and-validate-jwt-tokens-use-custom-jwt-middleware

当令牌过期或某些好友尝试在没有您的 SUPER_SECRET_KEY

的情况下发送 jwt 时,此代码会引发错误

您可以直接在令牌生成中和端点内部使用这些片段

[HttpGet]
public ActionResult<List<Dictionary<string, object>>> findAllEmployees()
{
    //get jwt from http received headers
    validationResponse = ValidateToken(jwt)
    //if you have a security platform, callhere instead
    //ValidateToken(jwt)
    //if validationResponse.isAllowed ....
    var list = this.employeeService.findAllEmployees();
    return Ok(list);
}

或使用像专业人士一样的中间件,以保持最终控制器的清洁

讲座

© www.soinside.com 2019 - 2024. All rights reserved.