9、vs2022_Web API服务端添加jwtToken验证

一、token验证机制

1.用户使用用户名密码来请求服务器

2.服务器进行验证用户的信息

3.服务器通过验证发送给用户一个token

4.客户端存储token,并在每次请求时附送这个token值,附带在http请求的header里

5.服务端验证token值,并返回数据

二、CommonLib库

1、添加工具包

Install-Package Microsoft.AspNetCore.Authentication.JwtBearer
Install-Package Microsoft.IdentityModel.Tokens
Install-Package System.IdentityModel.Tokens.Jwt
Install-Package Newtonsoft.Json

2、CommonLib库下,添加ResultModel.cs和JWTService.cs

namespace CommonLib
{
    public class ResultModel
    {
        public bool success { get; set; }
        public string? message { get; set; }
        public int count { get; set; }
        public object data { get; set; }
    }
}

 

using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

namespace CommonLib
{
    public static class JWTService
    {
        /// <summary>
        /// 创建token字符串
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public static string CreateToken(TokenModel model)
        {
            //将用户的部分信息存到了Claim中,using System.Security.Claims;
            var claims = new List<Claim> {
                new Claim("UserId",model.UserId),
                new Claim("UserName",model.UserName),
                new Claim("NickName",model.NickName),
            };
            // 用户的多个角色(如:Admin,System)全部赋予
            if (!string.IsNullOrWhiteSpace(model.Role))
            {
                claims.AddRange(model.Role.Split(',').Select(s => new Claim(ClaimTypes.Role, s)));
                claims.Add(new Claim("Role", model.Role));
            }
            //秘钥,using Microsoft.IdentityModel.Tokens;
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(model.SecurityKey));
            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);//密钥和加密方式
            //using System.IdentityModel.Tokens.Jwt;
            var jwt = new JwtSecurityToken(
                issuer: model.Issuer,  //颁发者
                audience: model.Audience,  //受众
                expires: DateTime.Now.AddMinutes(60),  //有效期
                signingCredentials: creds,
                claims: claims
            );
            var jwtHandler = new JwtSecurityTokenHandler();
            var token = jwtHandler.WriteToken(jwt);
            return token;
        }

        /// <summary>
        /// 解析token字符串,不检查有效性
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        public static TokenModel SerializeToken(string token)
        {
            //不校验,直接解析token
            var jwtToken = new JwtSecurityTokenHandler().ReadJwtToken(token);
            //using Newtonsoft.Json;
            var tokenModel = JsonConvert.DeserializeObject<TokenModel>(jwtToken.Payload.SerializeToJson());
            return tokenModel;
        }
    }
    /// <summary>
    /// 令牌
    /// </summary>
    public class TokenModel
    {
        public string UserId { get; set; }
        public string UserName { get; set; }
        public string NickName { get; set; }
        public string Role { get; set; }
        public string Issuer { get; set; }
        public string Audience { get; set; }
        public string SecurityKey { get; set; }
    }
}

三、WebApi_DEMO项目下,

1、在appsettings.json中配置jwt参数的值

{
  "Jwt": {
    "Issuer": "jwtIssuer", //颁发者
    "Audience": "jwtAudience", //可以给哪些客户端使用
    "SecurityKey": "abcdefghijklmnopqrstuvwxyz" //加密的Key,大于16位的字符串
  },
}

2、在Program.cs中配置jwt鉴权

//配置Jwt鉴权
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    //using Microsoft.AspNetCore.Authentication.JwtBearer;
    .AddJwtBearer(options =>{
        var tokenModel = builder.Configuration.GetSection("Jwt").Get<TokenModel>();
        var secretByte = Encoding.UTF8.GetBytes(tokenModel.SecurityKey);
        //using Microsoft.IdentityModel.Tokens;
        options.TokenValidationParameters = new TokenValidationParameters(){
            ValidateIssuer = true, //是否验证Issuer
            ValidateAudience = true, //是否验证Audience
            ValidateLifetime = true, //是否验证失效时间
            ValidIssuer = tokenModel.Issuer,
            ValidAudience = tokenModel.Audience, //这两项和前面签发jwt的设置一致
            IssuerSigningKey = new SymmetricSecurityKey(secretByte) // 拿到SecurityKey
        };
        options.Events = new JwtBearerEvents{
            OnChallenge = context =>{
                return Task.FromResult(0);
            },
            //403
            OnForbidden = context =>{
                return Task.FromResult(0);
            }
        };
});

3、在Program.cs中使用jwt鉴权

//使用鉴权授权
app.UseAuthentication();
app.UseAuthorization();

 四、使用EF构建登录信息,获取token

1、新建数据库表sys_User

create table sys_User(
    id nvarchar(50) PRIMARY KEY NOT NULL,
    name nvarchar(50) NULL,
    nickname nvarchar(50) NULL,
    password nvarchar(50) NOT NULL,
    role_id nvarchar(50) NOT NULL
    )
go
--添加测试数据
insert into sys_User  values ('zhou','周金辉','生之韵','123','admin')
insert into sys_User  values ('an','安安','安若子渔','456','system')
go

2、WebApi_DEMO项目下,新建Model文件夹,添加sys_User.cs

    public class sys_User
    {
        [Key]
        public string id { get; set; }
        public string name { get; set; }
        public string nickname { get; set; }
        public string password { get; set; }
        public string role_id { get; set; }

    }

3、WebApi_DEMO项目下,新建Repository文件夹,添加DemoDbContext.cs

namespace WebApi_DEMO.Repository
{
    public class DemoDbContext : DbContext
    {
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer(@"server=127.0.0.1;database=demo;uid=sa;pwd=1234");
        }
        public DbSet<sys_User> users { get; set; }
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<sys_User>().ToTable("sys_User");
        }
    }
}

4、WebApi_DEMO项目下,Program.cs文件注入服务

builder.Services.AddDbContext<DemoDbContext>();
builder.Services.AddDatabaseDeveloperPageExceptionFilter(); //数据库异常筛选器

5、WebApi_DEMO项目下,新建API控制器,添加sys_LoginController

using CommonLib;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using WebApi_DEMO.Repository;

namespace WebApi_DEMO.Controllers
{
    /// <summary>
    /// 用户登录
    /// </summary>
    [Route("api/[controller]/[action]")]
    [ApiController]
    public class sys_LoginController : ControllerBase
    {
        private readonly DemoDbContext _context;
        private IConfiguration _configuration;
        public sys_LoginController(DemoDbContext context, IConfiguration configuration)
        {
            _context = context;
            _configuration = configuration;
        }
        /// <summary>
        /// 登陆获取token
        /// </summary>
        /// <param name="UId">用户ID</param>
        /// <param name="Pwd">密码</param>
        /// <returns></returns>
        [HttpGet]
        public async Task<ResultModel> LoginIn(string UId, string Pwd)
        {
            var user = await _context.users.Where(u => u.id == UId && u.password == Pwd).FirstOrDefaultAsync();
            if (user != null)
            {
                //读取配置信息中的jwt公共数据
                var tokenModel = _configuration.GetSection("Jwt").Get<TokenModel>();
                //读取用户传入的信息
                tokenModel.UserId = user.id;
                tokenModel.UserName = user.name;
                tokenModel.NickName = user.nickname;
                tokenModel.Role = user.role_id;
                var token = JWTService.CreateToken(tokenModel);
                return new ResultModel
                {
                    success = true,
                    message = "登陆成功",
                    count = token.Count(),
                    data = token
                };
            }
            return new ResultModel
            {
                success = false,
                message = "登陆失败",
                count = 0,
                data = ""
            };
        }
        /// <summary>
        /// 通过token解析用户信息
        /// </summary>
        /// <param name="Authorization"></param>
        /// <returns></returns>
        [HttpGet]
        [Authorize]
        public IActionResult DeToken([FromHeader] string Authorization)
        {
            var str = Authorization.Replace("Bearer ", "");
            var token = JWTService.SerializeToken(str);
            return Ok(token);
        }
    }
}
sys_LoginController

 6、F5运行,运行结果如下

ps:获取的token字符串,可以登录https://jwt.io/ 网站解析token信息

 六、前端获取

<template>
  <button type="button" @click="getToken">获取token</button>
</template>

<script setup>
// 安装axios,npm install axios
import axios from "axios";
// 安装jwt-decode,npm install jwt-decode --save
import jwttoken from "jwt-decode";

const url = "http://127.0.0.1:8888/api/sys_Login/LoginIn";
const getToken = async () => {
  axios
    .get(url, {
      params: {
        UId: "zhou",
        Pwd: "123",
      },
    })
    .then((res) => {
      console.log(res.data);
      sessionStorage.token = res.data.data;
      sessionStorage.userInfo = jwttoken(res.data.data).NickName;
    });
};
</script>

ps:jwt-decode操作

// 安装
npm install jwt-decode --save
// 导入
import jwttoken from "jwt-decode";
// 解析
const decode = jwttoken(res.data).UserId;
// 保存UserId
localStorage.setItem("decode", decode);
// 获取解析的UserId
localStorage.getItem("decode");

 

posted @ 2022-04-07 10:13  生之韵  阅读(804)  评论(0)    收藏  举报