写了一个用户退出登录的方法,让Token立即过期,也可以应用在其他场景。
1.定义ApiControllerBase
[Produces("application/json")]
[ApiController]
public abstract class ApiControllerBase : ControllerBase
{
protected ClaimsPrincipal CurrentUser => this.HttpContext.User;
}
2.添加接口Controller
[ApiController]
[Route("[controller]")]
public class LoginController : ApiControllerBaer
{
private readonly ILoginService loginService;
public LoginController (ILoginService loginService)
{
this.loginService = loginService
}
[HttpPost("Logout")]
public void Logout()
{
this.loginService.Logout(this.CurrentUser);
}
}
3.添加业务逻辑层服务接口
public interface ILoginService
{
void Logout(ClaimsPrincipal currentUser);
}
4.添加业务逻辑层实现类
public class LoginService : ILoginService
{
private readonly ICaching cache;
public LoginService (ICaching cache)
{
this.cache = cache;
}
public void Logout (ClaimsPrincipal currentUser)
{
var jwtId= currentUser.GetJwtId();
var expiration = currentUser.GetJwtExpiration();
var expire = DateTimeOffset.FromUnixTimeSeconds(expiration).AddMinutes(5);//jwt默认有5分钟宽限时间
SetExpiration(jwtId,expire);
}
private const string CACHE_TOKEN_BLASKLIST_KEY = "CACHE:TOKEN:BLACKLIST";
public void SetExpiration(string jwtId,DateTimeOffset expire)
{
var key = $"{CACHE_TOKEN_BLASKLIST_KEY } : {jwtId}";
this.cache.SetString(key,jwtId, new DistributedCacheEntryOptions
{
AbsoluteExpiration = expire
});
}
}
5.添加静态类扩展方法
public static class Extensions
{
public static string GetJwtId(this ClaimsPrincipal parincipal)
{
var res = parincipal.Claims.SingleOrDefault(p=> p.Type == JwtClaimTupes.JwtId);//添加JWT校验时new一个guid保存到Claim的JwtId中,例如:new Claim(JwtClaimTypes.JwtId, Guid.NewGuid().ToString())
if(res == null)
thew new Exception("无法获取用户JwtId。");
return res.Value;
}
public static long GetJwtExpiration(this ClaimsPrincipal parincipal)
{
var res = parincipal.Claims.SingleOrDefault(p=> p.Type ==JwtClaimTupes.Expiration);
if(res == null)
thew new Exception("无法获取用户Expiration。");
return Convert.ToInt64(res.Value);
}
}
6.添加缓存扩展方法服务接口
public interface ICaching
{
void SetString(string key,string value, DistributedCacheEntryOptions options);
}
7.添加缓存扩展方法服务实现类
public class Caching : ICaching
{
private readonly IDistributedCache chche;
public Caching(IDistributedCache chche)
{
this.cache = cache;
}
public void SetString(string key, string value, DistributedCacheEntryOptions options)
{
cache.SetString(key, value, options);
}
}