通俗地来讲,JWT是能代表用户身份的令牌,可以使用JWT令牌在api接口中校验用户的身份以确认用户是否有访问api的权限。
授权:这是使用JWT的最常见方案。一旦用户登录,每个后续请求将包括JWT,允许用户访问该令牌允许的路由,服务和资源。
在身份验证中,当用户使用其凭据成功登录时,将返回JSONWeb令牌。由于令牌是凭证,因此必须非常小心以防止出现安全问题。一般情况下,您不应该将令牌保留的时间超过要求。
每当用户想要访问受保护的路由或资源时,用户代理应该使用承载模式发送JWT,通常在Authorization标头中,标题的内容应如下所示:
应用程序向授权服务器请求授权;
校验用户身份,校验成功,返回token;
应用程序使用访问令牌访问受保护的资源。
JWT的实现方式是将用户信息存储在客户端,服务端不进行保存。每次请求都把令牌带上以校验用户登录状态,这样服务就变成了无状态的,服务器集群也很好扩展。
更多理论知识可以查看官网,或者查看相关网友的文章,如下推荐文章:
在nuget里面引用jwt集成的程序包,这里需要注意的是,如果你用的是.NETCore1的框架的话,程序包版本选择7
添加数据访问模拟api,新建控制器ValuesController
其中api/value1是可以直接访问的,api/value2添加了权限校验特性标签[Authorize]
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
namespace jwtWebAPI.Controllers
{
[ApiController]
public class ValuesController : ControllerBase
{
[HttpGet]
[Route("api/values1")]
public ActionResult<IEnumerable<string>> values1()
{
return new string[] { "value1", "value1" };
}
/**
* 该接口用Authorize特性做了权限校验,如果没有通过权限校验,则http返回状态码为401
* 调用该接口的正确姿势是:
* 1.登陆,调用api/Auth接口获取到token
* 2.调用该接口 api/value2 在请求的Header中添加参数 Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOiIxNTYwMzM1MzM3IiwiZXhwIjoxNTYwMzM3MTM3LCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiemhhbmdzYW4iLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjUwMDAiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjUwMDAifQ.1S-40SrA4po2l4lB_QdzON_G5ZNT4P_6U25xhTcl7hI
* Bearer后面有空格,且后面是第一步中接口返回的token值
* */
[HttpGet]
[Route("api/value2")]
[Authorize]
public ActionResult<IEnumerable<string>> value2()
{
//这是获取自定义参数的方法
var auth = HttpContext.AuthenticateAsync().Result.Principal.Claims;
var userName = auth.FirstOrDefault(t => t.Type.Equals(ClaimTypes.NameIdentifier))?.Value;
return new string[] { "访问成功:这个接口登陆过的用户都可以访问", $"userName={userName}" };
}
}
}
添加模拟登陆生成Token的api,新建控制器AuthController
这里模拟一下登陆校验,只验证了用户密码不为空即通过校验,真实环境完善校验用户和密码的逻辑。
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
namespace jwtWebAPI.Controllers
{
[ApiController]
public class AuthController : Controller
{
/// <summary>
/// 通过账号+密码获取Token
/// </summary>
/// <param name="userName"></param>
/// <param name="pwd"></param>
/// <returns>Token</returns>
[AllowAnonymous]
[HttpGet]
[Route("api/auth")]
public IActionResult GetToken(string userName, string pwd)
{
if (!string.IsNullOrEmpty(userName))
{
//每次登陆动态刷新
Const.ValidAudience = userName + pwd + DateTime.Now.ToString();
// push the user’s name into a claim, so we can identify the user later on.
//这里可以随意加入自定义的参数,key可以自己随便起
var claims = new[]
{
new Claim(JwtRegisteredClaimNames.Nbf,$"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}") ,
new Claim (JwtRegisteredClaimNames.Exp,$"{new DateTimeOffset(DateTime.Now.AddMinutes(3)).ToUnixTimeSeconds()}"),
new Claim(ClaimTypes.NameIdentifier, userName)
};
//sign the token using a secret key.This secret will be shared between your API and anything that needs to check that the token is legit.
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Const.SecurityKey));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
//.NET Core’s JwtSecurityToken class takes on the heavy lifting and actually creates the token.
var token = new JwtSecurityToken(
//颁发者
issuer: Const.Domain,
//接收者
audience: Const.ValidAudience,
//过期时间(可自行设定,注意和上面的claims内部Exp参数保持一致)
expires: DateTime.Now.AddMinutes(3),
//签名证书
signingCredentials: creds,
//自定义参数
claims: claims
);
return Ok(new
{
token = new JwtSecurityTokenHandler().WriteToken(token)
});
}
else
{
return BadRequest(new { message = "username or password is incorrect." });
}
}
}
}
Startup添加JWT验证的相关配置
文章为作者独立观点,不代表股票交易接口观点