实体模型
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;// 配置ClaimsIdentityClaimsIdentity 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.把数据库录入的路径改为错误的路径