.NET鉴权授权

gitee仓储地址
---------------------------------2022-03-30分界线-----------------------------------
一种是cookie鉴权授权,一种是token鉴权授权,先把权限授予它,才能鉴定它的权限是否符合我的权限校验

一.鉴权cookie方式

1.在program中添加鉴权授权中间件
2.在控制器某个方法上添加鉴权特性
3.在program中添加

点击查看代码
builder.Services.AddAuthentication("Cookies").AddCookie(o =>
{
    o.LoginPath = "/Login/NoLogin";//鉴权不通过就跳到以下路径
});

4.添加一个控制器LoginController

点击查看代码
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;

namespace AuthDemo.Api.Controllers
{
    [Route("[controller]/[action]")]
    [ApiController]
    public class LoginController : ControllerBase
    {
        [HttpGet]
        public async Task<string> NoLoginAsync()
        {
            return "您还没有登录!";
        }
    }
}

5.在login控制器中添加一个方法

点击查看代码
        [HttpPost]
        public async Task<string> LoginSucess(string userName,string password)
        {
            //判断当前的用户名和密码
            if (userName=="Ace"&&password=="666")
            {
                //如果符合当前条件,则实例化一个实体,保存当前数据
                ClaimsIdentity claimsIdentity = new ClaimsIdentity("Ctm");
                claimsIdentity.AddClaim(new ( ClaimTypes.Name, userName));
                claimsIdentity.AddClaim(new(ClaimTypes.NameIdentifier, "1"));
                //cookies与program添加的鉴权架构一致
                await HttpContext.SignInAsync("Cookies",new ClaimsPrincipal(claimsIdentity));
                return "登录成功!";
            }
            else
            {
                return "登录失败!";
            }
        }

二.自定义token鉴权 自定义鉴权策略

1.新增一个文件夹CtmAuthentication,新增一个类文件TokenAuthenticationHandler,继承于IAuthenticationHandler接口,实现接口
2.TokenAuthenticationHandler类里的代码如下

点击查看代码
using Microsoft.AspNetCore.Authentication;
using System.Security.Claims;

namespace AuthDemo.Api.CtmAuthentication
{
    public class TokenAuthenticationHandler : IAuthenticationHandler
    {
        private AuthenticationScheme _scheme;
        private HttpContext _httpContext;
        /// <summary>
        /// 鉴权初始化
        /// </summary>
        /// <param name="scheme">鉴权架构名称</param>
        /// <param name="context">HttpContext</param>
        /// <returns></returns>
        public async Task InitializeAsync(AuthenticationScheme scheme, HttpContext context)
        {
            _scheme = scheme;
            _httpContext = context;
        }
        /// <summary>
        /// 鉴权
        /// </summary>
        /// <returns></returns>
        public async Task<AuthenticateResult> AuthenticateAsync()
        {
            string token = _httpContext.Request.Headers["Authorization"];
            if (token=="jaden")
            {
                ClaimsIdentity claimsIdentity = new("ctm");
                claimsIdentity.AddClaims(new List<Claim>
                {
                    new Claim(ClaimTypes.Name,"jaden"),
                    new Claim(ClaimTypes.NameIdentifier,"6")
                });
                var claimsPrincipal = new ClaimsPrincipal(claimsIdentity);
                return await Task.FromResult(AuthenticateResult.Success(new AuthenticationTicket(claimsPrincipal,_scheme.Name)));
            }
            return await Task.FromResult(AuthenticateResult.Fail("token错误,请重新登录"));
        }
        /// <summary>
        /// 未登录操作
        /// </summary>
        /// <param name="properties"></param>
        /// <returns></returns>
        public async Task ChallengeAsync(AuthenticationProperties? properties)
        {
            _httpContext.Response.Redirect("/Login/NoLogin");
        }
        /// <summary>
        /// 鉴权失败的操作
        /// </summary>
        /// <param name="properties"></param>
        /// <returns></returns>
        public async Task ForbidAsync(AuthenticationProperties? properties)
        {
            _httpContext.Response.StatusCode = 403;
        }

        
    }
}


3.修改program中的代码,如下

点击查看代码
using AuthDemo.Api.CtmAuthentication;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
#region 注册鉴权架构
//cookie
//builder.Services.AddAuthentication("Cookies").AddCookie(o =>
//{
//    o.LoginPath = "/Login/NoLogin";//鉴权不通过就跳到以下路径
//});
//自定义token验证
builder.Services.AddAuthentication(op =>
{
    //把自定义的鉴权方案添加到鉴权架构中
    //token是个名字,下面的代表Scheme name方案名字
    op.AddScheme<TokenAuthenticationHandler>("token","ctmToken");
    op.DefaultAuthenticateScheme = "token";
    op.DefaultChallengeScheme = "token";
    op.DefaultForbidScheme = "token";
});
#endregion
var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}
//鉴权
app.UseAuthentication();
//授权
app.UseAuthorization();

app.MapControllers();

app.Run();


4.然后用postman或者apipost中测试,token中输入一些字符,发现token中存在这些字符,下面让我们继续改造,其实token就是存在我们发送请求的head文件里的

三.授权策略

1.在program中的鉴权策略下添加如下代码

点击查看代码
/*
 自定义授权时,
 控制器上加的Authorize授权,
 后面记得加当前名称'MyPolicy',
 才能匹配到当前的授权方案(一般配置为常量)
 */
//自定义授权
builder.Services.AddAuthorization(op =>
{
    //判断当前的授权方案的
    op.AddPolicy(AuthorizationConts.MyPolicy, p => p.RequireClaim(ClaimTypes.NameIdentifier, "6"));
});

新增一个常量类AuthorizationConts,存放一个常量MyPolicy,值也是这个
2.在WeatherForecastController控制器中的Authorize鉴权特性中添加常量,代表的意思是鉴权时匹配我们自定义的鉴权
代码如下:

点击查看代码
using AuthDemo.Api.Consts;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace AuthDemo.Api.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class WeatherForecastController : ControllerBase
    {
        private static readonly string[] Summaries = new[]
        {
        "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
    };

        private readonly ILogger<WeatherForecastController> _logger;

        public WeatherForecastController(ILogger<WeatherForecastController> logger)
        {
            _logger = logger;
        }
        [Authorize(AuthorizationConts.MyPolicy)]
        [HttpGet(Name = "GetWeatherForecast")]
        public IEnumerable<WeatherForecast> Get()
        {
            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = DateTime.Now.AddDays(index),
                TemperatureC = Random.Shared.Next(-20, 55),
                Summary = Summaries[Random.Shared.Next(Summaries.Length)]
            })
            .ToArray();
        }
    }
}

经过以上改造就完成了自定义授权

四.授权断言

1.什么叫授权断言?
首先判定你当前用户有没有这个身份,比如说你的name有没有,有我则继续判断匹配不匹配,没有则直接报错
2.program中的自定义授权改为如下代码

点击查看代码
//自定义授权
builder.Services.AddAuthorization(op =>
{
    //判断当前的授权方案的
    //op.AddPolicy(AuthorizationConts.MyPolicy, p => p.RequireClaim(ClaimTypes.NameIdentifier, "6"));

    //授权断言
    //先判断user的类型是不是NameIdentifier,如果是,则判断当前值匹配不匹配
    //如果不是则直接报错
    op.AddPolicy(AuthorizationConts.MyPolicy,p=>
    p.RequireAssertion(
        a=>a.User.HasClaim(c=>c.Type==ClaimTypes.NameIdentifier) &&
        a.User.Claims.First(c=>c.Type.Equals(ClaimTypes.NameIdentifier)).Value=="6"
    ));
});

---------------------------------2022-03-31分界线-----------------------------------
---------------------------------2022-04-02分界线-----------------------------------

五.自定义授权与双授权策略(多scheme)

合起来的方案
1.创建一个CtmAuthorizations文件夹,创建一个MyAuthorizationHandler类,
MyAuthorizationHandler继承于AuthorizationHandler泛型抽象类
代码如下

点击查看代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;

namespace AuthDemo.Api.CtmAuthorizations
{
	public class MyAuthorizationHandler : AuthorizationHandler<MyAuthorizationHandler>, IAuthorizationRequirement
	{
		private readonly string userId;

		public MyAuthorizationHandler(string userId)
		{
			this.userId = userId;
		}
		/// <summary>
		/// 重写 AuthorizationHandler 父类中的 HandleRequirementAsync 方法
		/// </summary>
		/// <param name="context"></param>
		/// <param name="requirement"></param>
		/// <returns></returns>
		protected override async Task HandleRequirementAsync(
			AuthorizationHandlerContext context,
			MyAuthorizationRequirement requirement)
		{
			if (context.User.HasClaim(c => c.Type == ClaimTypes.NameIdentifier)
			&& context.User.Claims.First(c => c.Type.Equals(ClaimTypes.NameIdentifier)).Value == userId)
			{
				context.Succeed(requirement);
			}
		}
	}
}

2.program中的代码为:

点击查看代码
using System.Security.Claims;
using AuthDemo.Api.Consts;
using AuthDemo.Api.CtmAuthentication;
using AuthDemo.Api.CtmAuthorizations;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
#region 注册鉴权架构
//cookie
//builder.Services.AddAuthentication("Cookies").AddCookie(o =>
//{
//    o.LoginPath = "/Login/NoLogin";//鉴权不通过就跳到以下路径
//});
//自定义token验证 鉴权策略
builder.Services.AddAuthentication(op =>
{
	//把自定义的鉴权方案添加到鉴权架构中
	//token是个名字,下面的代表Scheme name方案名字
	op.AddScheme<TokenAuthenticationHandler>("token", "ctmToken");
	op.DefaultAuthenticateScheme = "token";
	op.DefaultChallengeScheme = "token";
	op.DefaultForbidScheme = "token";
});
/*
 自定义授权时,
 控制器上加的Authorize授权,
 后面记得加当前名称'MyPolicy',
 才能匹配到当前的授权方案(一般配置为常量)
 */
//自定义授权
// builder.Services.AddAuthorization(op =>
// {
// 	//判断当前的授权方案的
// 	//op.AddPolicy(AuthorizationConts.MyPolicy, p => p.RequireClaim(ClaimTypes.NameIdentifier, "6"));

// 	//授权断言
// 	//先判断user的类型是不是NameIdentifier,如果是,则判断当前值匹配不匹配
// 	//如果不是则直接报错
// 	op.AddPolicy(AuthorizationConts.MyPolicy, p =>
// 	p.RequireAssertion(
// 		a => a.User.HasClaim(c => c.Type == ClaimTypes.NameIdentifier) &&
// 		a.User.Claims.First(c => c.Type.Equals(ClaimTypes.NameIdentifier)).Value == "6"
// 	));
// });

//自定义授权
builder.Services.AddAuthorization(op =>
{
	op.AddPolicy(AuthorizationConts.MyPolicy, p => p.Requirements.Add(new MyAuthorizationHandler("6")));
});
#endregion
var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
	app.UseSwagger();
	app.UseSwaggerUI();
}
//鉴权
app.UseAuthentication();
//授权
app.UseAuthorization();

app.MapControllers();

app.Run();

---------------------------------2022-04-04分界线-----------------------------------
分开的方案
在使用双授权方案时,这两个策略必须同事通过才可以,否则授权失败
双授权方案与单授权方案基本一致,唯一不一样的就是注册policy的时候,注册两次,控制器的鉴权验证也写两次,将MyAuthorizationHandler复制一次即可,
将自定义授权方式换了一个

六.多鉴权架构

下午写这段
多鉴权架构下,只要成功一个,那么鉴权即认为成功
在控制器下加这段,并且打开program中cookie鉴权的注释
[Authorize(AuthenticationSchemes = $"token,Cookies")]
持续更新

七.授权和鉴权的绑定

1.修改program中的代码

点击查看代码
using System.Security.Claims;
using AuthDemo.Api.Consts;
using AuthDemo.Api.CtmAuthentication;
using AuthDemo.Api.CtmAuthorizations;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
#region 注册鉴权架构
//cookie
builder.Services.AddAuthentication("Cookies").AddCookie(o =>
{
	o.LoginPath = "/Login/NoLogin";//鉴权不通过就跳到以下路径
});
//自定义token验证 鉴权策略
builder.Services.AddAuthentication(op =>
{
	//把自定义的鉴权方案添加到鉴权架构中
	//token是个名字,下面的代表Scheme name方案名字
	op.AddScheme<TokenAuthenticationHandler>("token", "ctmToken");
	// op.DefaultAuthenticateScheme = "token";
	op.DefaultChallengeScheme = "token";
	op.DefaultForbidScheme = "token";
});
/*
 自定义授权时,
 控制器上加的Authorize授权,
 后面记得加当前名称'MyPolicy',
 才能匹配到当前的授权方案(一般配置为常量)
 */
//自定义授权
// builder.Services.AddAuthorization(op =>
// {
// 	//判断当前的授权方案的
// 	//op.AddPolicy(AuthorizationConts.MyPolicy, p => p.RequireClaim(ClaimTypes.NameIdentifier, "6"));

// 	//授权断言
// 	//先判断user的类型是不是NameIdentifier,如果是,则判断当前值匹配不匹配
// 	//如果不是则直接报错
// 	op.AddPolicy(AuthorizationConts.MyPolicy, p =>
// 	p.RequireAssertion(
// 		a => a.User.HasClaim(c => c.Type == ClaimTypes.NameIdentifier) &&
// 		a.User.Claims.First(c => c.Type.Equals(ClaimTypes.NameIdentifier)).Value == "6"
// 	));
// });

//自定义授权
builder.Services.AddAuthorization(op =>
{
	op.AddPolicy(AuthorizationConts.MyPolicy,
	p => p.AddAuthenticationSchemes("token").Requirements.Add(new MyAuthorizationHandler("6")));
	// op.AddPolicy(AuthorizationConts.MyPolicy, p => p.Requirements.Add(new MyAuthorizationHandler("6")));
	op.AddPolicy(AuthorizationConts.MyPolicy2, p => p.AddAuthenticationSchemes("Cookies").Requirements.Add(new MyAuthorizationHandler2("Ace")));
});
#endregion
var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
	app.UseSwagger();
	app.UseSwaggerUI();
}
//鉴权
app.UseAuthentication();
//授权
app.UseAuthorization();

app.MapControllers();

app.Run();

将poliy中添加schemes,为token,并注释默认scheme即可
2.注意scheme策略名称需要一直,鉴权和授权策略名称是一致的
修改控制器中的代码,输入你要鉴权的方案

点击查看代码
                [Authorize(AuthorizationConts.MyPolicy2)]
		public IEnumerable<WeatherForecast> Get()
		{
			return Enumerable.Range(1, 5).Select(index => new WeatherForecast
			{
				Date = DateTime.Now.AddDays(index),
				TemperatureC = Random.Shared.Next(-20, 55),
				Summary = Summaries[Random.Shared.Next(Summaries.Length)]
			})
			.ToArray();
		}

这里我用的是mypolicy2的鉴权方案,当你用哪个鉴权方案时,它就用哪个鉴权,并且对它进行授权
--------------------------------------2022-04-05分界线--------------------------------------------

八.session授权绑定鉴权

session本身是个字典,并且是个作用域生命周期,session存在缓存中,并可以设置过期时间
key:sessionId,value:Dictonary<sessionKey,SessionValue>(字符串字典)
1.首先要想实现seesion自定义实现,必须用到缓存(MemoryCache),并且新增一个文件夹Core,新增一个MySession及IMySession接口,MySession继承于IMySession
program类代码如下:

点击查看代码
using System.Security.Claims;
using AuthDemo.Api.Consts;
using AuthDemo.Api.Core;
using AuthDemo.Api.CtmAuthentication;
using AuthDemo.Api.CtmAuthorizations;
using Microsoft.Extensions.Caching.Memory;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
// builder.Services.AddSingleton<IMemoryCache, MemoryCache>();
builder.Services.AddMemoryCache();
builder.Services.AddScoped<IMySession, MySession>();
#region 注册鉴权架构
//cookie
// builder.Services.AddAuthentication("Cookies").AddCookie(o =>
// {
// 	o.LoginPath = "/Login/NoLogin";//鉴权不通过就跳到以下路径
// });

//自定义token验证 鉴权策略
builder.Services.AddAuthentication(op =>
{
	//把自定义的鉴权方案添加到鉴权架构中
	//token是个名字,下面的代表Scheme name方案名字

	op.AddScheme<SessionAuthenicationHandler>("session", "ctmSession");
	op.DefaultAuthenticateScheme = "session";
	op.DefaultChallengeScheme = "session";
	op.DefaultForbidScheme = "session";
});
/*
 自定义授权时,
 控制器上加的Authorize授权,
 后面记得加当前名称'MyPolicy',
 才能匹配到当前的授权方案(一般配置为常量)
 */
//自定义授权
// builder.Services.AddAuthorization(op =>
// {
// 	//判断当前的授权方案的
// 	//op.AddPolicy(AuthorizationConts.MyPolicy, p => p.RequireClaim(ClaimTypes.NameIdentifier, "6"));

// 	//授权断言
// 	//先判断user的类型是不是NameIdentifier,如果是,则判断当前值匹配不匹配
// 	//如果不是则直接报错
// 	op.AddPolicy(AuthorizationConts.MyPolicy, p =>
// 	p.RequireAssertion(
// 		a => a.User.HasClaim(c => c.Type == ClaimTypes.NameIdentifier) &&
// 		a.User.Claims.First(c => c.Type.Equals(ClaimTypes.NameIdentifier)).Value == "6"
// 	));
// });

//自定义授权
// builder.Services.AddAuthorization(op =>
// {
// 	op.AddPolicy(AuthorizationConts.MyPolicy,
// 	p => p.AddAuthenticationSchemes("token").Requirements.Add(new MyAuthorizationHandler("6")));
// 	// op.AddPolicy(AuthorizationConts.MyPolicy, p => p.Requirements.Add(new MyAuthorizationHandler("6")));
// 	op.AddPolicy(AuthorizationConts.MyPolicy2, p => p.AddAuthenticationSchemes("Cookies").Requirements.Add(new MyAuthorizationHandler2("Ace")));
// });
#endregion
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
	app.UseSwagger();
	app.UseSwaggerUI();
}
//鉴权
app.UseAuthentication();
//授权
app.UseAuthorization();

app.MapControllers();

app.Run();

具体的思路,在代码中已经详细标明了
2.MySession和IMySession接口代码如下:

IMySession
using Microsoft.Extensions.Caching.Memory;

namespace AuthDemo.Api.Core
{
	public interface IMySession
	{
		string GetString(string key);
		void InitSession(string sessionId, IMemoryCache memoryCache);
		void SetString(string key, string value);
	}
}
MySession
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Memory;

namespace AuthDemo.Api.Core
{

	public class MySession : IMySession
	{
		/*
			1.session是这样去保存数据的,每个用户都有一个sessionId,
			2.根据sessionId去获取用户的数据
			3.每个用户的数据保存在内存中,这样可以让session更短(就是浏览器的缓存中)
			4.sessionId是唯一的,每个用户的sessionId是不一样的
			5.sessionId是在第一次访问的时候生成的,第一次访问后,sessionId就会被保存在cookie中
			6.所以我们需要在我们设计的session类中,定义一个私有sessionId,并定义一个缓存
			7.这样在初始化Session的时候,将初始化Session的方法调用一下,把SessionId和缓存传进去
			8.在获取数据的时候,根据sessionId去缓存中获取数据
			9.在设置数据的时候,根据sessionId去缓存中设置数据
		*/
		private string sessionId;
		private IMemoryCache memoryCache;
		/// <summary>
		/// 初始化Session,在鉴权验证方法中被调用
		/// </summary>
		/// <param name="sessionId"></param>
		/// <param name="memoryCache"></param>
		public void InitSession(string sessionId, IMemoryCache memoryCache)
		{
			this.memoryCache = memoryCache;
			this.sessionId = sessionId;

		}
		/// <summary>
		/// 通过key获取存储的值
		/// </summary>
		/// <param name="key"></param>
		/// <returns></returns>
		public string GetString(string key)
		{
			// 获取SeesionId 并根据SeesionId拿到当前用户存储的键值对
			if (memoryCache.TryGetValue(sessionId, out Dictionary<string, string> dic))
			{
				return dic[key];
			}
			else
			{
				return default;
			}

		}

		public void SetString(string key, string value)
		{
			// 获取SeesionId 并根据SeesionId拿到当前用户存储的键值对
			if (memoryCache.TryGetValue(sessionId, out Dictionary<string, string> dic))
			{
				dic[key] = value;
			}
		}
	}
}

3.SessionAuthenicationHandler代码如下:

SessionAuthenicationHandler
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using AuthDemo.Api.Core;
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Caching.Memory;

namespace AuthDemo.Api.CtmAuthentication
{
	public class SessionAuthenicationHandler : IAuthenticationHandler
	{
		/// <summary>
		/// 定义一个缓存
		/// </summary>
		private readonly IMemoryCache _cache;
		/// <summary>
		/// 定义一个自定义的Session
		/// </summary>
		private readonly IMySession _session;
		/// <summary>
		/// 定义一个SessionId
		/// </summary>
		private string _sessionId;
		/// <summary>
		/// 定义上下文
		/// </summary>
		private HttpContext _context;
		/// <summary>
		/// 定义鉴权策略
		/// </summary>
		public AuthenticationScheme _scheme;
		/// <summary>
		/// 构造函数传入缓存,及session
		/// </summary>
		/// <param name="cache"></param>
		/// <param name="session"></param>
		public SessionAuthenicationHandler(IMemoryCache cache, IMySession session)
		{
			this._session = session;
			this._cache = cache;
		}
		/// <summary>
		///
		/// </summary>
		/// <param name="scheme"></param>
		/// <param name="context"></param>
		/// <returns></returns>
		public async Task InitializeAsync(AuthenticationScheme scheme, HttpContext context)
		{
			//1.初始化时将策略赋值,将上下文赋值
			this._scheme = scheme;
			this._context = context;
			//从上下文中的cookie取值,没有则创建一个
			//判断当前缓存没有seesionid并且实际的数据也没有,则创建一个新的sessionid
			if (!TryGetSession(out string id) || !_cache.TryGetValue(_sessionId, out Dictionary<string, string> value))
			{
				//创建一个sessionid,为guid
				var sessionId = Guid.NewGuid().ToString();
				_sessionId = sessionId;
				//将上下文中的返回值的cookie,设置一个sessionid
				_context.Response.Cookies.Append(".AspNetCore.Session", sessionId);
				//将sessionid当作键值,将空的字典当作值,并设置过期时间
				_cache.Set<Dictionary<string, string>>(sessionId, new Dictionary<string, string>(), TimeSpan.FromMinutes(20));
			}
		}
		/// <summary>
		/// 从上下文中的cookie中取值,输出sessionId
		/// 将sesionid赋值到当前私有变量sessionId中,
		/// 如果能获取到值则返回true,否则返回false
		/// </summary>
		/// <param name="sessionId"></param>
		/// <returns></returns>
		private bool TryGetSession(out string sessionId)
		{
			var hasSession = _context.Request.Cookies.TryGetValue(".AspNetCore.Session", out sessionId);
			_sessionId = sessionId;
			return hasSession;
		}
		/// <summary>
		/// 鉴权方法
		/// </summary>
		/// <returns></returns>
		public async Task<AuthenticateResult> AuthenticateAsync()
		{
			//从缓存中获取sessionid,如果没有则返回false
			if (_cache.TryGetValue(_sessionId, out Dictionary<string, string> value))
			{
				//将当前sessionId和键值对组成新的键值对,存入缓存中,并设置过期时间为20分钟
				_cache.Set<Dictionary<string, string>>(_sessionId, value, TimeSpan.FromMinutes(20));
				//调用session的初始化方法,将sessionId和缓存中的键值对传入
				_session.InitSession(_sessionId, _cache);
				//将当前sessionId赋值给ClaimsPrincipal
				ClaimsIdentity claimsIdentity = new("ctm");
				claimsIdentity.AddClaims(new List<Claim>
				{
					new Claim(ClaimTypes.NameIdentifier,_sessionId)
				});
				//最终返回成功的结果
				return await Task.FromResult(AuthenticateResult.Success(new AuthenticationTicket(new ClaimsPrincipal(claimsIdentity), null, _scheme.Name)));
			}
			else
			{
				return await Task.FromResult(AuthenticateResult.Fail("Session已经过期"));
			}
		}

		public async Task ChallengeAsync(AuthenticationProperties properties)
		{
			_context.Response.Redirect("/Login/NoLogin");
		}

		public async Task ForbidAsync(AuthenticationProperties properties)
		{
			_context.Response.StatusCode = 403;
		}
	}



}

小一周完成了

posted @ 2022-03-29 17:47  rookiexwang  阅读(224)  评论(0编辑  收藏  举报