基于 JWT Bearer 的身份认证方案
认证流程
- 匿名访问资源,server 响应 401
- client 跳转至登录页面
- client 请求 RSA 公钥,用户输入账号、密码
- client 对密码执行 RSA 加密,请求 login
- server 验证账号、密码,通过之后,签发包含用户标识的 JWT
- client 使用 JWT 设置 Authorization,scheme type 为 Bearer
- server 验证 JWT 是否合法,是否过期,验证通过后,完成身份认证
密码安全
不存储原始的明文密码
- client 对密码执行 RSA 加密,然后传递密文
- server 使用私钥对密码进行解密,成功之后,结合数据库中记录的 salt 验证密码的 MD5
关键实现
JWT Authentication
引用 package
Microsoft.AspNetCore.Authentication.JwtBearer
配置 Authentication Scheme
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
// your configuration
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();
// after routing, so that route information is available for authentication decisions
app.UseAuthentication();
// after authentication
app.UseAuthorization();
app.UseEndpoints();
}
}
生成 JWT
public string GenerateToken(string userId)
{
var claims = new Claim[]
{
new Claim(ClaimTypes.NameIdentifier, "Your_Identitier"),
//add any claim
};
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("Your_SecurityKey"));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
issuer: ,
audience: ,
signingCredentials: creds,
claims: claims,
notBefore: ,
expires:
);
return new JwtSecurityTokenHandler().WriteToken(token);
}
获取身份信息
var value = context?.User?.Claims
?.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier)
?.Value;
RSA Encryption and Decryption
为保证跨平台,使用第三方的 package
XC.RSAUtil
public static string RSAEncrypt(string publicKey, string dataToEncrypt)
{
using var rsa = new RsaPkcs1Util(Encoding.UTF8, publicKey, null, 1024);
return rsa.Encrypt(dataToEncrypt, RSAEncryptionPadding.Pkcs1);
}
public static string RSADecrypt(string privateKey, string dataToDecrypt)
{
using var rsa = new RsaPkcs1Util(Encoding.UTF8, null, privateKey, 1024);
return rsa.Decrypt(dataToDecrypt, RSAEncryptionPadding.Pkcs1);
}