(1)导入Pomelo.EntityFrameworkCore.Mysql
(2)导入Swashbuckle.AspNetCore
(3)导入Microsoft.AspNetCore.Authentication.JwtBearer
一.前期配置
1.Startup.cs
using CRUD4.Models;
using CRUD4.Services;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using System.Security.Claims;
using System.Security.Cryptography;
namespace CRUD4
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
// Add your services here
string connectionString = Configuration.GetConnectionString("DefaultConnection");
services.AddScoped<ITeacherRepository, TeacherRepository>();
services.AddScoped<ITeacherService, TeacherService>();
services.AddScoped<RsaSecurityKey>();
services.AddHttpContextAccessor();
services.AddScoped<ITokenBlacklistService, TokenBlacklistService>();
services.AddLogging();
//swager
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "Your API", Version = "v1" });
});
//database
services.AddDbContext<MyContext>(options =>
options.UseMySql
(connectionString, ServerVersion.AutoDetect(connectionString))
);
// 生成 RSA 密钥对
RSA rsa = RSA.Create(2048);
var privateKey = rsa;
var publicKey = rsa.ExportRSAPublicKey();
// 将密钥保存到服务中,以便后续使用
services.AddSingleton(privateKey);
services.AddSingleton(publicKey);
// 配置 JWT 认证
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false,
ValidateAudience = false,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new RsaSecurityKey(privateKey)
};
options.Events = new JwtBearerEvents
{
OnTokenValidated = async context =>
{
var blacklistService = context.HttpContext.RequestServices.GetRequiredService<ITokenBlacklistService>();
var token = context.Request.Headers["Authorization"].ToString();
if (token != null && await blacklistService.IsBlacklisted(token.Substring(7)))
{
context.Fail("This token is blacklisted");
}
}
};
});
//添加自定义接口访问权限 在接口上加[Authorize(Policy = "admin")]
services.AddAuthorization(options =>
{
options.AddPolicy("admin", policy =>
{
policy.RequireAuthenticatedUser(); // 用户必须经过身份验证
policy.RequireClaim(ClaimTypes.Name, "T2024002"); // 用户必须具有指定的声明(即指定的信息为""里的信息)
});
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
// Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.),
// specifying the Swagger JSON endpoint.
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "Your API V1");
});
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
//添加身份验证中间件
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}
2.Program.cs
namespace CRUD4;
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
3.appsettings.json
{
"ConnectionStrings": {
"DefaultConnection": "Server=localhost;Database=demo1;User=root;Password=123456;"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
4.统一返回类R
namespace CRUD4.Commons
{
public class R<T>
{
public int Code { get; set; } // 编码:1成功,0和其它数字为失败
public string Msg { get; set; } // 错误信息
public T Data { get; set; } // 数据
public Dictionary<string, object> Map { get; set; } = new Dictionary<string, object>(); // 动态数据
public static R<T> Success(T data)
{
return new R<T> { Data = data, Code = 1 };
}
public static R<T> Error(string msg)
{
return new R<T> { Msg = msg, Code = 0 };
}
public R<T> Add(string key, object value)
{
this.Map[key] = value;
return this;
}
}
}
二.模型文件夹
1.数据库配置
using Microsoft.EntityFrameworkCore;
namespace CRUD4.Models
{
public class MyContext : DbContext
{
public DbSet<Teacher> Teachers { get; set; }
public DbSet<Course> Courses { get; set; }
public MyContext(DbContextOptions<MyContext> options)
:base(options)
{
}
}
}
2.Teacher类
namespace CRUD4.Models
{
public class Teacher
{
public int Id { get; set; }
public string Name { get; set; }
public string Code { get; set; }
public string Password { get; set; }
}
}
3.TeacherLocalModel类
用于教师登录操作,使用Code教师编号和Password登录
namespace CRUD4.Models
{
public class TeacherLoginModel
{
public string Code{ get; set; }
public string Password { get; set; }
}
}
4.ITeacherRepository
namespace CRUD4.Models
{
public interface ITeacherRepository
{
void AddTeacher(Teacher teacher);
void RemoveTeacherByCode(string code);
void UpdateTeacher(Teacher teacher);
Teacher GetTeacherById(int id);
IEnumerable<Teacher> GetTeacherByName(string name);
Teacher GetTeacherByCode(string code);
IEnumerable<Teacher> GetAllTeachers();
Teacher Login(TeacherLoginModel teacherLoginModel);
}
}
5.TeacherRepository
namespace CRUD4.Models
{
public class TeacherRepository : ITeacherRepository
{
private readonly MyContext _context;
public TeacherRepository(MyContext context) {
_context = context;
}
public void AddTeacher(Teacher teacher)
{
_context.Teachers.Add(teacher);
_context.SaveChanges();
}
public void RemoveTeacherByCode(string code)
{
var teacher=_context.Teachers.FirstOrDefault(t=>t.Code == code);
_context.Teachers.Remove(teacher);
_context.SaveChanges(true);
}
public void UpdateTeacher(Teacher teacher)
{
var teacher1=_context.Teachers.FirstOrDefault(t=>t.Id == teacher.Id );
_context.Teachers.Entry(teacher1).CurrentValues.SetValues(teacher);
_context.SaveChanges();
}
public IEnumerable<Teacher> GetAllTeachers()
{
return _context.Teachers.ToList();
}
public Teacher GetTeacherByCode(string code)
{
return _context.Teachers.FirstOrDefault(t => t.Code == code);
}
public Teacher GetTeacherById(int id)
{
return _context.Teachers.FirstOrDefault(t => t.Id == id);
}
public IEnumerable<Teacher> GetTeacherByName(string name)
{
return _context.Teachers.Where(t => t.Name.Contains(name)).ToList();
}
public Teacher Login(TeacherLoginModel teacherLoginModel)
{
return _context.Teachers.FirstOrDefault(t => t.Code == teacherLoginModel.Code && t.Password == teacherLoginModel.Password);
}
}
}
6.ITokenBlacklistService
用于退出功能把token拉进黑名单
namespace CRUD4.Models
{
public interface ITokenBlacklistService
{
Task<bool> IsBlacklisted(string token);
Task AddTokenToBlacklist(string token);
}
}
7.TokenBlacklistService
namespace CRUD4.Models
{
public class TokenBlacklistService : ITokenBlacklistService
{
// 这里假设黑名单存储在内存中的集合中,您可以根据实际需求将其替换为数据库或其他持久化存储方式
private readonly HashSet<string> _blacklistedTokens;
public TokenBlacklistService()
{
_blacklistedTokens = new HashSet<string>();
}
public Task<bool> IsBlacklisted(string token)
{
// 模拟异步操作
return Task.FromResult(_blacklistedTokens.Contains(token));
}
public Task AddTokenToBlacklist(string token)
{
// 去掉 "Bearer " 前缀
var tokenValue = token.Substring("Bearer ".Length);
// 模拟异步操作
_blacklistedTokens.Add(tokenValue);
return Task.CompletedTask;
}
}
}
三.Service层
1.ITeacherService
using CRUD4.Commons;
using CRUD4.Models;
namespace CRUD4.Services
{
public interface ITeacherService
{
R<string> AddTeacher(Teacher teacher);
R<string> DeleteTeacher(string code);
R<string> UpdateTeacher(Teacher teacher);
R<Teacher> GetTeacherById(int id);
R<IEnumerable<Teacher>> GetTeacherByName(string name);
R<Teacher> GetTeacherByCode(string code);
R<IEnumerable<Teacher>> GetAllTeachers();
R<string> Login(TeacherLoginModel teacherLoginModel);
R<string> Logout();
}
}
2.TeacherService
using CRUD4.Commons;
using CRUD4.Models;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
namespace CRUD4.Services
{
public class TeacherService : ITeacherService
{
private readonly ITeacherRepository _repository;
private readonly RsaSecurityKey _securityKey;
private readonly IDictionary<string, string> _tokens;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly ITokenBlacklistService _tokenBlacklistService;
private readonly ILogger<TeacherService> _logger;
public TeacherService(ITeacherRepository repository,RsaSecurityKey securityKey,
IHttpContextAccessor httpContextAccessor,
ILogger<TeacherService> logger,
ITokenBlacklistService tokenBlacklistService)
{
_repository = repository;
_securityKey = securityKey;
_tokens = new Dictionary<string, string>();
_httpContextAccessor = httpContextAccessor;
_logger = logger;
_tokenBlacklistService = tokenBlacklistService;
}
public R<string> AddTeacher(Teacher teacher)
{
var teacher1=_repository.GetTeacherByCode(teacher.Code);
if(teacher1 == null)
{
_repository.AddTeacher(teacher);
return R<string>.Success("新增成功");
}
return R<string>.Error("新增失败");
}
public R<string> DeleteTeacher(string code)
{
var teacher=_repository.GetTeacherByCode(code);
if(teacher != null)
{
_repository.RemoveTeacherByCode(code);
return R<string>.Success("删除成功");
}
return R<string>.Error("删除失败,没有此编号的老师");
}
public R<string> UpdateTeacher(Teacher teacher)
{
var teacher1 = _repository.GetTeacherById(teacher.Id);
if(teacher1 != null)
{
_repository.UpdateTeacher(teacher);
return R<string>.Success("修改成功");
}
return R<string>.Error("修改失败,没有此编号的老师");
}
public R<IEnumerable<Teacher>> GetAllTeachers()
{
return R<IEnumerable<Teacher>>.Success(_repository.GetAllTeachers());
}
public R<Teacher> GetTeacherByCode(string code)
{
var teacher = _repository.GetTeacherByCode(code);
if (teacher != null)
{
return R<Teacher>.Success(teacher);
}
return R<Teacher>.Error("没有这个编号的老师");
}
public R<Teacher> GetTeacherById(int id)
{
var teacher = _repository.GetTeacherById(id);
if (teacher != null)
{
return R<Teacher>.Success(teacher);
}
return R<Teacher>.Error("没有这个id的老师");
}
public R<IEnumerable<Teacher>> GetTeacherByName(string name)
{
var teacher = _repository.GetTeacherByName(name);
if (teacher != null)
{
return R<IEnumerable<Teacher>>.Success(teacher);
}
return R<IEnumerable<Teacher>>.Error("没有这个名字的老师");
}
public R<string> Login(TeacherLoginModel teacherLoginModel)
{
var teacher=_repository.Login(teacherLoginModel);
if(teacher != null)
{
var token = GenerateToken(teacher.Code);
// 登录成功后将 Teacher 对象存储在 HttpContext.Items 中
//_contextAccessor.HttpContext.Items["LoggedInTeacher"] = teacher;
return R<string>.Success(token);
}
return R<string>.Error("登录失败");
}
/*
public R<string> Logout()
{
if (_contextAccessor.HttpContext.Items.ContainsKey("LoggedInTeacher"))
{
var teacher = (Teacher)_contextAccessor.HttpContext.Items["LoggedInTeacher"];
ClearToken(teacher.Code);
return R<string>.Success("退出成功");
}
else
{
return R<string>.Error("退出失败,必须先登录才能退出");
}
}
*/
public R<string> Logout()
{
if (_httpContextAccessor == null || _tokenBlacklistService == null)
{
_logger.LogError("HttpContextAccessor or TokenBlacklistService is null.");
return R<string>.Error("服务未正确配置");
}
var token = _httpContextAccessor.HttpContext.Request.Headers["Authorization"].FirstOrDefault();
if(token == null|| !token.StartsWith("Bearer "))
{
return R<string>.Error("退出失败");
}
// 去掉 "Bearer " 前缀
var tokenValue = token.Substring("Bearer ".Length);
// 调用添加到黑名单的方法
_tokenBlacklistService.AddTokenToBlacklist(tokenValue);
return R<string>.Success("退出成功");
}
public string GenerateToken(string tcode)
{
var signingCredentials = new SigningCredentials(_securityKey, SecurityAlgorithms.RsaSha256);
var claims = new[ ]
{
new Claim(ClaimTypes.Name,tcode)
};
var jwt=new JwtSecurityToken(
claims:claims,
signingCredentials:signingCredentials,
expires:DateTime.UtcNow.AddMinutes(30));
var token =new JwtSecurityTokenHandler().WriteToken(jwt);
return token;
}
public void ClearToken(string tcode)
{
if (_tokens.ContainsKey(tcode))
{
_tokens.Remove(tcode);
}
}
}
}
四.控制器层
1.TeacherController
using CRUD4.Models;
using CRUD4.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace CRUD4.Controllers
{
[ApiController]
[Route("api/teacher")]
public class TeacherController : Controller
{
private readonly ITeacherService _service;
public TeacherController(ITeacherService service)
{
_service = service;
}
//Post: api/teacher/add
[HttpPost("add")]
public IActionResult AddTeacher(Teacher teacher)
{
return Ok(_service.AddTeacher(teacher));
}
//Delete: api/teacher/delete/T2024003
[HttpDelete("delete/{code}")]
public IActionResult DeleTeacher(string code)
{
return Ok(_service.DeleteTeacher(code));
}
//Post: api/teacher/update
[HttpPost("update")]
public IActionResult UpdateTeacher(Teacher teacher)
{
return Ok(_service.UpdateTeacher(teacher));
}
//Get: api/teacher/1
[HttpGet("{id}")]
public IActionResult GetTeacherById(int id)
{
return Ok(_service.GetTeacherById(id));
}
//Get: api/teacher/getByCode/T2024001
[HttpGet("getByCode/{code}")]
public IActionResult GetTeacherByCode(string code)
{
return Ok(_service.GetTeacherByCode(code));
}
//Get: api/teacher/getByName/李老师
[HttpGet("getByName/{name}")]
public IActionResult GetTeacherByName(string name)
{
return Ok(_service.GetTeacherByName(name));
}
//Get: api/teacher
[HttpGet]
[Authorize(Policy ="admin")]
public IActionResult GetAllTeachers()
{
return Ok(_service.GetAllTeachers());
}
//Post: api/teacher/login
[HttpPost("login")]
public IActionResult Login(TeacherLoginModel teacherLoginModel)
{
return Ok(_service.Login(teacherLoginModel));
}
//Post: api/teacher/logout
[HttpPost("logout")]
[Authorize]
public IActionResult Logout()
{
return Ok(_service.Logout());
}
[HttpGet("index")]
public IActionResult Index()
{
return View();
}
}
}