- A+
JWT鉴权授权
一、授权
NuGet授权包:System.IdentityModel.Tokens.Jwt
这里是api登陆的接口 返回的是jwt
[HttpPost("Login")]
public IActionResult Login(UserInfor userInfor)
{
//加密后的密码
userInfor.Password = _MD5.Md5Helper.encrypt(userInfor.Password);
//数据校验
var user = this.userRespository.FindUser(userInfor);
if (user!=null)
{
var claims = new Claim[]
{
//new Claim(ClaimTypes.Name, user.Account),
new Claim("Id",user.Id.ToString()), //id写进去
new Claim("Account",user.Account), //账号写进去
};
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("SDMC-CJAS1-SAD-DFSFA-SADHJVF-VF"));
var token = new JwtSecurityToken(
issuer: "http://localhost:6060",
audience: "http://localhost:5000",
claims: claims,
notBefore: DateTime.Now,
expires: DateTime.Now.AddHours(1),
signingCredentials: new SigningCredentials(key, SecurityAlgorithms.HmacSha256)
);
var jwtToken = new JwtSecurityTokenHandler().WriteToken(token);
return Ok(ApiResult.ApiResultHelper.Success(jwtToken));
}
else
{
return Ok(ApiResult.ApiResultHelper.Error("账号或密码有误"));
}
}
返回的格式入下
{
"Code": 200,
"Total": 0,
"Msg": "操作成功",
"Data": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImN0eSI6IkpXVCJ9.eyJJZCI6IjQiLCJBY2NvdW50IjoiYWRtaW4zIiwibmJmIjoxNjUzMjM5MTM1LCJleHAiOjE2NTMyNDI3MzUsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6NjA2MCIsImF1ZCI6Imh0dHA6Ly9sb2NhbGhvc3Q6NTAwMCJ9.CHzckeeTd0iUbuxpWlyYewCG7jr4e_AQwOaJfMoBsxM"
}
JWT的token包含三部分数据:
Header:头部,通常头部有两部分信息: 声明类型type,这里是JWT(type=jwt) 加密算法,自定义(rs256/base64/hs256) 我们会对头部进行base64加密(可解密),得到第一部分数据 Payload:载荷,就是有效数据,一般包含下面信息: 用户身份信息-userid,username(注意,这里因为采用base64加密,可解密,因此不要存放敏感信息) 注册声明:如token的签发时间,过期时间,签发人等 这部分也会采用base64加密,得到第二部分数据 Signature:base64加密,签名,是整个数据的认证信息。一般根据前两步的数据,再加上服务的的密钥(secret,盐)(不要泄漏,最好周期性更换),通过加密算法生成。用于验证整个数据完整和可靠性 一个JWT实际上就是一个字符串,它由三部分组成,头部、载荷与签名。
头部(header)
头部用于描述关于该JWT的最基本的信息,例如其类型以及签名所用的算法等。这也可以 被表示成一个JSON对象。
{
"typ":"JWT",
"alg":"HS256"
}
这就是头部的明文内容,第一部分说明他是一个jwt,第二部分则指出签名算法用的是HS256算法。
然后将这个头部进行BASE64编码,编码后形成头部:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
载荷(payload)
载荷就是存放有效信息的地方,有效信息包含三个部分:
(1)标准中注册的声明(建议但不强制使用)
iss: jwt签发者 sub: jwt所面向的用户 aud: 接收jwt的一方 exp: jwt的过期时间,这个过期时间必须要大于签发时间 nbf: 定义在什么时间之前,该jwt都是不可用的. iat: jwt的签发时间 jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
(2)公共的声明
公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息. 但不建议添加敏感信息,因为该部分在客户端可解密.
(3)私有的声明
私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64 是对称解密的,意味着该部分信息可以归类为明文信息。
{
"sub":"1234567890",
"name":"tengshe789",
"admin": true
}
上面就是一个简单的载荷的明文,接下来使用base64加密:
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9
签证(signature)
jwt的第三部分是一个签证信息,这个签证信息由三部分组成:
header (base64后的) payload (base64后的) secret 这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第 三部分。
结论:
1 jwt的一个有规则的token
2 它有三部分组成:Header.payload.signature,每部分都是通过base64加密而成的
3 jwt每个部分都是可以解密的
二、鉴权
NuGet鉴权包:Microsoft.AspNetCore.Authentication.JwtBearer
直接给控制器加鉴权的特性
[Authorize]
中间件
//鉴权
app.UseAuthentication();
//授权
app.UseAuthorization();
IOC容器
//这里写的是授权的使用说明 (c.SwaggerDoc底下的代码)
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "Test0522.API", Version = "v1" });
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey,
Description = "直接在下框中输入Bearer {token} (注意两者之间是一个空格)",
Name = "Authorization",
BearerFormat = "JWT",
Scheme = "Bearer"
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
}
},
new string[]{ }
}
});
});
//JWT鉴权
services.AddCustomJWT();
我这里写的扩展方法返回的鉴权服务
public static class IOExtend
{
public static IServiceCollection AddCustomJWT(this IServiceCollection services)
{
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("SDMC-CJAS1-SAD-DFSFA-SADHJVF-VF")),
ValidateIssuer = true,
ValidIssuer = "http://localhost:6060",
ValidateAudience = true,
ValidAudience = "http://localhost:5000",
ValidateLifetime = true,
ClockSkew = TimeSpan.FromMinutes(60)
};
});
return services;
}
}
效果如下 只需要输入token码即可访问接口