我有一个正在运行的会员专用网站,可以通过登录等方式正常工作。 我现在需要支持单点登录,我将在 JWT 令牌中接收配置文件的用户名,然后让用户登录。 将发送此请求的外部系统除了用户名之外不知道任何其他信息 - 因此密码不会在令牌中共享,也不可能。
JWT 已被选为实现此目的的首选方法。我们将使用密钥来交换信息,密钥当然只有发送者和接收者知道。
我正在寻找一个简单的示例,说明在发送端和接收端如何从代码角度来看。 接收端将是一个 WebAPI 端点,它将处理登录,然后在登录成功时重定向到会员专用网站的首页。
它是用C#开发的。
通常,用户/密码会被交换为新的 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 变量来隐藏它的秘密并在生产环境中尽可能地保护它
如果理解了前面的步骤,您只需要使用以下方法之一:
智威汤逊一代
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;
}
}
当令牌过期或某些好友尝试在没有您的 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);
}
或使用像专业人士一样的中间件,以保持最终控制器的清洁