实体模型
public class BaseModel
{
public int Id { get; set;}
}
public class Authorization : BaseModel
{
public string Route { get; set; }
public string AuthorizationName { get; set; }
}
public class User : BaseModel
{
public string UserName { get; set; }
public string Password { get; set; }
}
public class UserAuthorizationMapping : BaseModel
{
public int UserId { get; set; }
public int AuthorizationId { get; set; }
}
自定义Session
public interface IMySession
{
void InitSession(IMemoryCache memoryCache, string sessionId);
string? GetString(string key);
void SetString(string key, string value);
}
public class MySession : IMySession
{
private IMemoryCache _memoryCache;
private string _sessionId;
public void InitSession(IMemoryCache memoryCache, string sessionId)
{
_sessionId = sessionId;
_memoryCache = memoryCache;
}
public string? GetString(string key)
{
// 获取SessionId,并根据这个拿到当前用户存储的键值对
if(_memoryCache.TryGetValue(_sessionId,out Dictionary<string,string>? dic))
{
if(dic == null)
{
return null;
}
if(dic.TryGetValue(key,out string? dicValue))
{
return dicValue;
}
}
return null;
}
public void SetString(string key,string value)
{
if (_memoryCache.TryGetValue(_sessionId, out Dictionary<string, string>? dic))
{
if (dic != null)
{
dic[key] = value;
}
}
}
}
自定义鉴权架构
public class SessionAuthenicationHandler : IAuthenticationHandler
{
private readonly IMemoryCache _cache;
private readonly IMySession _session;
private AuthenticationScheme _scheme;
private HttpContext _context;
private string _sessionId;
public SessionAuthenicationHandler(IMemoryCache cache, IMySession session)
{
_cache = cache;
_session = session;
}
/// <summary>
/// 初始化身份验证处理程序。 作为此方法的一部分,处理程序应从请求和方案中初始化它所需的任何内容
/// </summary>
/// <param name="scheme"></param>
/// <param name="context"></param>
/// <returns></returns>
public async Task InitializeAsync(AuthenticationScheme scheme, HttpContext context)
{
_scheme = scheme;
_context = context;
if (!TryGetSession(out string id) || !_cache.TryGetValue(_sessionId, out var cookie))
{
var sessionId = Guid.NewGuid().ToString();
_sessionId = sessionId;
context.Response.Cookies.Append(".AspNetCore.Sessions", sessionId);
_cache.Set<Dictionary<string, string>>(_sessionId, new Dictionary<string, string>(), TimeSpan.FromMinutes(1));
}
}
/// <summary>
/// 对当前请求进行身份验证。
/// </summary>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public Task<AuthenticateResult> AuthenticateAsync()
{
// 尝试从缓存中获取数据
if(_cache.TryGetValue(_sessionId,out Dictionary<string,string> value))
{
// 重新滑动配置缓存过期
_cache.Set<Dictionary<string,string>>(_sessionId,value,TimeSpan.FromMinutes(1));
// 初始化Session
_session.InitSession(_cache,_sessionId);
// 注意,这里存储到HttpContext.Items中
_context.Items["session"] = _session;
// 配置ClaimsIdentity
ClaimsIdentity claimsIdentity = new ClaimsIdentity("Ctm");
claimsIdentity.AddClaims(
new List<Claim>
{
new Claim(ClaimTypes.NameIdentifier,_sessionId)
}
);
return Task.FromResult(AuthenticateResult.Success(new AuthenticationTicket(new ClaimsPrincipal(claimsIdentity),null,_scheme.Name)));
}else
{
return Task.FromResult(AuthenticateResult.Fail("Session过期,请重新登录"));
}
}
/// <summary>
/// 质询当前请求。
/// </summary>
/// <param name="properties"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public async Task ChallengeAsync(AuthenticationProperties? properties)
{
_context.Response.Redirect("/Login/NoLogin");
}
/// <summary>
/// 禁止当前请求
/// </summary>
/// <param name="properties"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public async Task ForbidAsync(AuthenticationProperties? properties)
{
_context.Response.StatusCode = 403;
}
private bool TryGetSession(out string id)
{
var has = _context.Request.Cookies.TryGetValue(".AspNetCore.Sessions",out id);
_sessionId = id;
return has;
}
}
自定义授权
public class CtmAuthorizationFilter : Attribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
var session = context.HttpContext.Items["session"] as IMySession;
var route = context.HttpContext.Request.Path.Value;
var auth = session.GetString("Auth");
if(auth != null)
{
var aurhorizations = JsonConvert.DeserializeObject<List<Authorization>>(auth);
if(aurhorizations == null || aurhorizations.Count < 1)
{
context.Result = new JsonResult("没有录入权限数据") { StatusCode = 403 };
}
if (aurhorizations.Any(x => x.Route != route))
{
context.Result = new JsonResult("无权限") { StatusCode = 403 };
}
}else
{
context.Result = new JsonResult("请先登录") { StatusCode = 403 };
}
}
}
注册
builder.Services.AddSingleton<IMemoryCache,MemoryCache>();
builder.Services.AddScoped<IMySession,MySession>();
builder.Services.AddAuthentication(opt =>
{
opt.AddScheme<SessionAuthenicationHandler>("session","sessionScheme");
opt.DefaultChallengeScheme = "session";
opt.DefaultAuthenticateScheme = "session";
opt.DefaultForbidScheme = "session";
});
app.UseAuthentication();
app.UseAuthorization();
使用
public class LoginController : BaseController
{
private readonly LoginBLL _loginBLL;
public LoginController(LoginBLL loginBLL)
{
_loginBLL = loginBLL;
}
[HttpGet("CheckLogin")]
public async Task<bool> CheckLoginAsync(string userName, string password)
{
var user = await _loginBLL.CheckLoginAsync(userName, password);
if (user == null)
{
return false;
}
var authorizations = await _loginBLL.GetAuthorizationsAsync(user.Id);
Session.SetString("Auth", JsonConvert.SerializeObject(authorizations));
return true;
}
}
public class TestController : BaseController
{
[CtmAuthorizationFilter]
[HttpGet("GetTime")]
public async Task<string> GetTimeAsync()
{
return await Task.FromResult(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
}
}
结果
1.在不登录的情况下访问GetTime
2.先登录,再访问GetTime
3.把数据库录入的路径改为错误的路径