前言
簡單整理一下閘道器中的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介面,得到為:
那麼這樣就在閘道器實現了身份簽名和認證了。那麼如果其他服務需要進行認證的話,那麼可以新增相同的認證方式即可。
細節篇介紹一下這個的原始碼。
結
下一節跨域請求的安全問題。