一.简介
本案例使用c# ASP.NET 10编写WEB API网络服务器,通过jwt令牌机制为通过验证的用户签发令牌token,(jwt基础教学见本栏目007篇,SQLite数据库操作见006篇),本节接007优化,
我们的思路是:提供一个公共未加密的用户账号注册api给用户访问,用户访问支api时需用POST网络请求的方式,并向云服务器提供一个我们规定的用户账号Person类对象.属性里有账号和密码等信息,用json格式上传,服务器收到注册请求时,提前申请方的账号去比对数据库中的用户,如果用户名已经存在,拒绝注册,如果不存在,将申请方的账号和密码增加进数据库,注册成功,
用户有了账号密码后就可以访问我们另一支登录api,同样也是post方式请求,并上传用户类对象,服务器会拿申请者的用户名去查找数据库中有无这个用户,如果有,再比对他的密码是否正确,都正确,登录成功,发给他一个jwt令牌token,否则拒绝登录.
拿到的token令牌可以访问到服务器jwt加密的api
二,实现方式
1.建立用户对象模型类Person
cs
namespace Esp32_Server.Models
{
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public string Power { get; set; }
public string Email { get; set; }
}
}
2.封装数据库操作类
见006篇
3.创建用户注册账号类Login.cs
cs
using Esp32_Server.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Data.Sqlite;
using Microsoft.IdentityModel.Tokens;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
namespace Esp32_Server.Controllers
{
/// <summary>
/// 用户注册登录类
/// </summary>
[Route("api/[controller]")]
[ApiController]
public class Login : ControllerBase
{
private List<Person> people; //用户数据库list对象
//查詢全部新聞
[HttpGet]
public IEnumerable<Person> Get()
{
people = Linq_table.GetAllPeople(); //查询数据表中全部数据
return people;
}
//注册一个账户
[HttpPost]
public IActionResult Post(Person value)
{
// 1. 先检查内存中是否已存在(可选,作为第一道防线)
var people = Linq_table.GetAllPeople();//获取数据库中所有用户对象
if (people.Any(p => p.Name.Trim() == value.Name.Trim()))
{
return Conflict(new { message = "名称已存在,请修改。" });
}
try
{
// 2. 尝试写入数据库
Linq_table.InsertPerson(value.Name, value.Power, value.Email);
}
catch (Exception ex)
{
// 返回 400 或 409 错误给前端,而不是让程序崩溃
return BadRequest(new { message = "注册失败,用户名已经存在。" });
}
//注册成功
return Ok(Linq_table.GetAllPeople());//查询所有数据库(测试用),实际使用时删除
}
}
}
4.创建用户登录验证控制器类MemberLogin.cs
注意jwt密匙要设置为和服务器Program.cs配置的jwt密匙一样
cs
using Esp32_Server.Administrator;
using Esp32_Server.Controllers;
using Esp32_Server.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
namespace Esp32_Server.Member
{
/// <summary>
/// 用户登录验证类,传入一个用户类对象,如果数据库有这个用户名,且密码正确,则返回一个JWT令牌
/// </summary>
[Route("api/[controller]")]
[ApiController]
public class MemberLogin : ControllerBase
{
private List<Person> people; //用户数据库list对象
/// <summary>
/// 登录验证,传入一个用户类对象,如果用户名和密码正确,则返回一个JWT令牌
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public IActionResult Login([FromBody] Person request)
{
// 1. 获取数据库中的所有用户
people = Linq_table.GetAllPeople();
// 2. 使用 LINQ 的 FirstOrDefault 查找是否存在同名用户
var user = people.FirstOrDefault(p => p.Name == request.Name);
// 3. 验证逻辑:
// 如果 user 为 null,说明没找到;如果找到,再比对密码
if (user != null && user.Power == request.Power)
{
// 验证通过,生成令牌
var token = GenerateJwtToken(user.Name);
return Ok(new { token });
}
// 4. 用户名不存在或密码错误,统一返回 Unauthorized
return Unauthorized(new { message = "用户名或密码错误" });
}
//生成令牌
private string GenerateJwtToken(string username)
{
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("服务器设置的jwt秘钥"));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
issuer: "yourdomain.com",
audience: "yourdomain.com",
claims: new[] { new Claim(ClaimTypes.Name, username) },
expires: DateTime.Now.AddHours(8),//设置token令牌的有效期为8小时
signingCredentials: credentials);
return new JwtSecurityTokenHandler().WriteToken(token);
}
}
}
5.注册测试
服务器用http方式运行,
查询所有数据库的账户信息,这支api实际是管理员的,不允许被其他人访问,后期会删除,
请求方式: GET
URL :http://localhost:5264/api/login
返回:服务器数据库所有用户信息(非常危险,后期不允许这支api被用户访问),他就是Login_GET这支api


我们可以看到,服务器数据库里现在有两个用户对象,现在测试新注册一个用户账号
请求方式:POST
报文Body: Person类格式的json数据
URL : :http://localhost:5264/api/login

可以看到,我们提交的账号密码成功注册,并写进了服务器数据库,至于id为什么是5,这是因为数据库的id是不可以被重复使用的,前面有人用过这个3的id,即使他删除了,数据库也不会去重复使用这些使用过的id
我们故意再注册一次已经存在的这个小红账号,看看服务器会不会成功拒绝我们注册

成功拦截已存在的用户注入
6.登录测试
请求方式:POST
报文Body: Person类格式的json数据
URL : http://localhost:5264/api/MemberLogin
我们提交我们刚刚注册的这个
账号:"小红",
密码;"123456"
发起请求后,服务器拿账号和密码去数据库查找比对,找到了小红这个账号并且密码正确,服务器反馈给我们一个jwt令牌token,它的有限期是8小时,拿着这个token,我们就可以去访问到服务器其他用token加密的api了,
至于怎么访问加密的api, 007篇有基础原理教学,后续章节会出高级的封装用法
