ASP.NET Core 鉴权授权四(自定义Session)

实体模型

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.把数据库录入的路径改为错误的路径

posted @ 2024-08-07 16:54  leafroc  阅读(84)  评论(0)    收藏  举报