简介
OAUTH协议为用户资源的授权提供了一个安全的、开放而又简易的标准。同时,任何第三方都可以使用OAUTH认证服务,任何服务提供商都可以实现自身的OAUTH认证服务。
实现
1.准备工作
a. 新建一个ASP.Net Core Web API项目,运行时为.NETCore 6.0
b. 新建一个Controller用于新用户注册,Register( )
[HttpPost(Name = "Register"), AllowAnonymous]
public async Task<ResponseResult<bool>> Register(string userName, string password)
{
// 将用户的账号密码经过Hash后,将UserName与HashCode存入数据库
......
}
c. 新建一个Controller用于验证
[HttpGet(Name = "GetWeatherForecast")]
public async Task<ResponseResult<IEnumerable>> Get()
{
string strDateNow = await _baseServices.GetSysDatetimeAsync(0);
var dataReturn = Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)] +
"--" + strAppId + "--" + strDateNow
});
return base.SuccessResult(dataReturn);
}
2.生成Token
新建一个Controller用于用户登录,Login( )
[HttpPost(Name = "Login"), AllowAnonymous]
public async Task<ResponseResult<string>> Login(string userName, string password)
{
// 将用户加密后与数据库中该UserName对应的HashCode进行比对
if(ValidateUserPassword(userName, password))
{
......
//从数据库中读取并实例化用户对象
var user = GetUserInfo(userName);
var token = CreateToken(user);
return base.SuccessResult(token);
}
else
{
......
}
}
private string CreateToken(User user)
{
List<Claim> claims = new List<Claim>()
{
new Claim(ClaimTypes.Name, user.Name),
new Claim(ClaimTypes.Role, user.Role)
// 如果是微信账号登录,需要包含以下两个字段
//new Claim("openid", user.OpenId),
//new Claim("sesson_key", user.SessonKey)
};
// 获取用于加密的密钥
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(AppSettingsConfig.authClass.APISecretKey));
// 使用HmacSha256算法加密
var creds = new SigningCredentials(key,SecurityAlgorithms.HmacSha256Signature);
// 生成JwtToken对象
var token = new JwtSecurityToken(
claims: claims,
expires: DateTime.Now.AddHours(24),
signingCredentials: creds);
var jwt = new JwtSecurityTokenHandler().WriteToken(token);
return jwt;
}
CreateToken方法通过HmacSha256以配置文件中的密钥SecretKey对Claim信息进行对称加密,返回JWT Token.
*注意:Sha256加密算法要求SecretKey的长度不小于16位
返回的Token解析后类似以下格式:
3.验证Token前的准备
在Program.cs中配置Authentication与Authorize
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options => options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(AppSettingsConfig.authClass.APISecretKey)),
ValidateIssuer = false,
ValidateAudience = false
});
app.UseAuthentication();
app.UseAuthorization();
如果需要通过Swagger来进行API测试,还需要进行以下配置:
builder.Services.AddSwaggerGen(options =>
{
options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
{
Description = "请输入以下格式(\"bearer {token}\")",
In = ParameterLocation.Header,
Name = "Authorization",
Type = SecuritySchemeType.ApiKey
});
options.OperationFilter<SecurityRequirementsOperationFilter>();
});
配置生效后,Swagger页面的右上角会出现该图标:
4.验证Token并访问受保护的资源API
在窗口中输入Bear,空格后加上刚才Login成功后返回的Token字符串
请求成功:
如果Token不正确则返回HttpStatus:401 Unauthorized
5.基于用户角色的授权方式
对GetToken的方法进行修改,指定该用户的Role为Admin
private string CreateToken(User user)
{
List<Claim> claims = new List<Claim>()
{
new Claim(ClaimTypes.Name, user.Name),
new Claim(ClaimTypes.Role, "Admin")
}
};
修改Controller的Attribute,指定Authorize(Roles = "Customer")
[HttpGet(Name = "GetWeatherForecast"), Authorize(Roles = "Customer")]
public async Task<ResponseResult<IEnumerable<WeatherForecast>>> Get()
{
......
}
如果用原有的Token进行访问,将会返回HttpStatus: 403 Fobbiden
重新通过Login( )获取Token,再次访问成功。
总结
*注意:在增加了全局Authorize过滤器的情况下,对于Register和Login等不需要授权访问的API,可以加上AllowAnonymous过滤器,来允许匿名访问