iotgateway/WalkingTec.Mvvm/WalkingTec.Mvvm.Mvc/Auth/JwtAuth/TokenService.cs
2021-12-14 14:10:44 +08:00

156 lines
5.3 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using WalkingTec.Mvvm.Core;
using WalkingTec.Mvvm.Core.Auth;
using WalkingTec.Mvvm.Core.Extensions;
namespace WalkingTec.Mvvm.Mvc.Auth
{
public class TokenService : ITokenService
{
private readonly ILogger _logger;
private readonly JwtOption _jwtOptions;
private const Token _emptyToken = null;
private readonly Configs _configs;
private readonly IDataContext _dc;
public IDataContext DC => _dc;
public TokenService(
ILogger<TokenService> logger,
IOptionsMonitor<Configs> configs
)
{
_configs = configs.CurrentValue;
_jwtOptions = _configs.JwtOptions;
_logger = logger;
_dc = CreateDC();
}
public async Task<Token> IssueTokenAsync(LoginUserInfo loginUserInfo)
{
if (loginUserInfo == null)
throw new ArgumentNullException(nameof(loginUserInfo));
var signinCredentials = new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtOptions.SecurityKey)), SecurityAlgorithms.HmacSha256);
var cls = new List<Claim>()
{
new Claim(AuthConstants.JwtClaimTypes.Subject, loginUserInfo.ITCode.ToString())
};
if (string.IsNullOrEmpty(loginUserInfo.TenantCode) == false)
{
cls.Add(new Claim(AuthConstants.JwtClaimTypes.TenantCode, loginUserInfo.TenantCode.ToString()));
}
var tokeOptions = new JwtSecurityToken(
issuer: _jwtOptions.Issuer,
audience: _jwtOptions.Audience,
claims: cls,
expires: DateTime.Now.AddSeconds(_jwtOptions.Expires),
signingCredentials: signinCredentials
);
var refreshToken = new PersistedGrant()
{
UserCode = loginUserInfo.ITCode + "$`$" + loginUserInfo.TenantCode,
Type = "refresh_token",
CreationTime = DateTime.Now,
RefreshToken = Guid.NewGuid().ToString("N"),
Expiration = DateTime.Now.AddSeconds(_jwtOptions.RefreshTokenExpires)
};
_dc.AddEntity(refreshToken);
await _dc.SaveChangesAsync();
var token = new JwtSecurityTokenHandler().WriteToken(tokeOptions);
return await Task.FromResult(new Token()
{
AccessToken = token,
ExpiresIn = _jwtOptions.Expires,
TokenType = AuthConstants.JwtTokenType,
RefreshToken = refreshToken.RefreshToken
});
}
private IDataContext CreateDC()
{
string cs = "tokendefault";
if (_configs.Connections.Any(x => x.Key.ToLower() == cs) == false)
{
cs = "default";
}
return _configs.Connections.Where(x => x.Key.ToLower() == cs).FirstOrDefault().CreateDC();
}
/// <summary>
/// refresh token
/// </summary>
/// <param name="refreshToken">refreshToken</param>
/// <returns></returns>
public async Task<Token> RefreshTokenAsync(string refreshToken)
{
// 获取 RefreshToken
PersistedGrant persistedGrant = await _dc.Set<PersistedGrant>().Where(x => x.RefreshToken == refreshToken).SingleOrDefaultAsync();
if (persistedGrant != null)
{
// 校验 regresh token 有效期
if (persistedGrant.Expiration < DateTime.Now)
throw new Exception("refresh token 已过期");
// 删除 refresh token
_dc.DeleteEntity(persistedGrant);
await _dc.SaveChangesAsync();
var pair = persistedGrant.UserCode?.Split("$`$");
//生成并返回登录用户信息
var loginUserInfo = new LoginUserInfo()
{
ITCode = pair[0],
TenantCode = pair[1],
};
// 清理过期 refreshtoken
var sql = $"DELETE FROM {DC.GetTableName<PersistedGrant>()} WHERE Expiration<'{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}'";
_dc.RunSQL(sql);
_logger.LogDebug("清理过期的refreshToken【sql:{0}】", sql);
// 颁发 token
return await IssueTokenAsync(loginUserInfo);
}
else
{
return null;
}
}
/// <summary>
/// clear expired refresh tokens
/// </summary>
/// <returns></returns>
public async Task ClearExpiredRefreshTokenAsync()
{
var dataTime = DateTime.Now;
var mapping = _dc.GetTableName<PersistedGrant>();
var sql = $"DELETE FROM {mapping} WHERE Expiration<=@dataTime";
_dc.RunSQL(sql, new
{
dataTime = dataTime
});
await Task.CompletedTask;
}
}
}