重新整理 .net core 实践篇————网关中的身份签名认证[三十七]

前言

简单整理一下网关中的jwt,jwt用于授权认证的,其实关于认证授权这块https://www.cnblogs.com/aoximin/p/12268520.html 这个链接的时候就已经写了,当然只写到了4节,后面有10节没有写,是相对复杂的场景,后续会补齐。

正文

jwt 是json web tokens,是一种支持前面的数据结构。

至于什么是jwt的话,https://www.jianshu.com/p/576dbf44b2ae 这里有人写的比较好了。

然后前文也提及到为什么在网关做身份认证了,因为这样就不需要专门调用另外一个服务来实现身份认证,身份认证授权可以在网关和所以微服务同时生效。

教程直接在.net core文档里面搜索jwt即可查阅到。

那么就根据例子要演示一下:

首先加入对应的包:

在appsettings.json 中加入加密密钥:

"SecurityKey": "asdfghjklqwertyuiopzxcvbnm"

然后注入服务:

var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["SecurityKey"]));
services.AddSingleton(securityKey);
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
	.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
	{

	}).AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
	{
		options.TokenValidationParameters = new TokenValidationParameters
		{
			ValidateIssuer = true,
			ValidateAudience = true,
			ValidateLifetime = true,
			ClockSkew = TimeSpan.FromSeconds(30),
			ValidateIssuerSigningKey = true,
			ValidAudience = "localhost",
			ValidIssuer = "localhost",
			IssuerSigningKey = securityKey
		};
	});

上面ValidateIssuer 、ValidateAudience 、ValidateLifetime 分别是验证Issuer、Audience、Lifetime这三个的,其实Issuer、Audience验证和不验证的话影响不大,主要是因为jwt随时可以解密出来,就是经过base64位的转换。
加入中间件:

app.UseAuthentication();

app.UseAuthorization();

测试代码:

[HttpGet]
public async Task<IActionResult> JwtLogin([FromServices]SymmetricSecurityKey securityKey,string userName)
{
	List<Claim> claims = new List<Claim>();
	claims.Add(new Claim("Name", userName));
	var creds = new SigningCredentials(securityKey,SecurityAlgorithms.HmacSha256);
	var token = new JwtSecurityToken(
		 issuer:"localhost",
		 audience:"localhost",
		 claims:claims,
		 expires:DateTime.Now.AddMinutes(30),
		 signingCredentials:creds
		);
	var t = new JwtSecurityTokenHandler().WriteToken(token);
	return Content(t);
}

然后调用生成jwt:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJOYW1lIjoiMTIzIiwiZXhwIjoxNjI1NjE0NDkyLCJpc3MiOiJsb2NhbGhvc3QiLCJhdWQiOiJsb2NhbGhvc3QifQ.lQg70rMofgue9X_RQ1ft_NDmXyY2OJbTZodN4krVOUM

然后通过下面网址进行解密:

https://www.box3.cn/tools/jwt.html

然后来测试一下这个是否生效:

[ApiController]
[Route("[controller]")]
public class OrderController : Controller
{
	[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme+","+CookieAuthenticationDefaults.AuthenticationScheme)]
	public IActionResult oneApi()
	{
		return Content(User.FindFirst("name").Value);
	}
}

上面[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme+","+CookieAuthenticationDefaults.AuthenticationScheme)]的意思是可以通过jwt验证也可以通过cookie来验证。

为什么要这么写呢?因为:

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
	.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
	{

	}).AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options ....

上面写了两种方式,且AddCookie在前,那么如果只写Authorize,那么默认是cookie,如果AuthenticationSchemes 为JwtBearerDefaults.AuthenticationScheme,那么只有jwt。

一般我们的项目中用jwt,但是因为有些网站刚开始的时候觉得方便用了cookie,后来因为有app接口,那么需要添加jwt,这里不是只app接口不能用cookie,而是不太方便。

那么效果如下:

可以看到传递了一个Authoization的参数,这个参数是约定参数,那么值就是Bearer加空格,然后后面接的就是jwt了,这些是约定。

那么返回了123,这个123就是我们jwt中Claim的key为name的值,调用就是User.FindFirst("name").Value,还是相当方便的。

当然我们也可以通过cookie来进行认证:

[HttpGet]
public async Task<IActionResult> CookieLogin(string userName)
{
	var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme);
	identity.AddClaim(new Claim("Name", userName));
	await this.HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme,new ClaimsPrincipal(identity));
	return Content("login");
}

这样把cookie 传入到响应流中传递给前端。
然后访问:http://localhost:5000/account?username=ao

可以看到有个cookie。

那么访问一下刚才的oneApi接口,得到为:

那么这样就在网关实现了身份签名和认证了。那么如果其他服务需要进行认证的话,那么可以添加相同的认证方式即可。

细节篇介绍一下这个的源码。

下一节跨域请求的安全问题。

原文地址:https://www.cnblogs.com/aoximin/p/14979788.html