.Net初学 创建一个巨简单的.Net7 WebApi后端框架
工具
visual studio 2022
以下简称vs Visual Studio安装指南_visual studio安装教程_技术人小柒的博客-CSDN博客
sqlserver 2022
以下简称mssql SQL Server2022 Express和SSMS下载安装教程(超详细) (baidu.com)
redis
Redis下载安装图文教程(Windows版_超详细)_windows redis下载_Leeway啊樺的博客-CSDN博客
PDman
数据库设计,可以直接生成脚本,power design平替 PDMan数据库建模
创建项目
创建解决方案
打开vs点创建新项目,没什么可说的,有手就行,下一步
搜索框输入core,因为.net和.net core又在一起了。选择asp.net core web api,下一步
项目名称最好写的规范一点,一般都是 [公司名称.项目名称.net项目名称]和一些天花乱坠的标识,解决方案和项目放在同一目录去掉,很烦,项目总体的目录架构不太好看,然后把解决方案名称最好改掉,因为解决方案是项目的父级,最好是比项目名少一个节点。下一步
最后一步选择.net7版本,https勾掉,安全机制影响开发效率,有需要的加上就好。点创建。
完成,成功创建一个api项目,直接可以跑,把docker换成iis express
跑起来看到是core内置的swagger,方便测试服务接口用 try it out ==> Excute ,200就是成功。
项目层级
根据项目实际需要分层,我这里分了七层:(懒得重新创建了,直接用之前的项目截图)
从上到下分别是:
1.API接口层, 用于实现各种场景需求的服务,主要存放controller控制器
2.Cache缓存
3.Common辅助类层,存放一些公用的方法和帮助类
4.DAL数据访问层,主要一些基本的操作数据库的方法。
5.IRepository抽象层,因为我们用到了ioc容器,所以保存了一些控制反转的机制,用于存放抽象类
6.Model实体层,存放数据实体类,包括实现特定需求业务的实体,枚举,接口响应数据类型,调用其他接口的请求类型
7.Repository 业务逻辑层,需要实现上面的抽象层,达到控制反转的效果,同时相当于三层架构中的BLL层级,实现各项实际业务。
根据实际场景缩减或扩展。
实现登录功能
数据结构
表结构仅供参考,根据实际需求创建 。
这里创建好了直接生成脚本去执行
实体创建
然后在项目的model层创建一个entity文件夹,创建一个用户的实体类
内容:
using System; using System.ComponentModel.DataAnnotations.Schema; namespace Project.TM.WCore.Model.Entity.JCXX { /// /// 用户信息表 /// [Table("T_JCXX_User")] public class UserEntity { /// /// ID /// [Dapper.Key] public int Id { get; set; } /// /// 名称 /// public string? Name { get; set; } /// /// 用户名 /// public string? UserName { get; set; } /// /// 密码 /// public string? Password { get; set; } /// /// 性别 /// public bool Sex { get; set; } /// /// 年龄 /// public int Age { get; set; } /// /// 生日 /// public string? Birthday { get; set; } /// /// 联系方式 /// public string? Contact { get; set; } /// /// 职称 /// public string? Occupation { get; set; } /// /// 部门 /// public string? Department { get; set; } /// /// 邮箱 /// public string? Email { get; set; } /// /// 居住地 /// public string? City { get; set; } /// /// 公司 /// public string? Company { get; set; } /// /// 头像 /// public string? Avatar { get; set; } /// /// 标签 /// public int Tag { get; set; } /// /// 个人介绍 /// public string? Introductory { get; set; } /// /// 是否启用 /// public bool Isuse { get; set; } /// /// 部门/组织/角色 /// public string[]? role { get; set; } /// /// 创建人 /// public string? Creator { get; set; } /// /// 创建时间 /// public DateTime Createtime { get; set; } /// /// 更新人 /// public string? Updator { get; set; } /// /// 更新时间 /// public DateTime Updatetime { get; set; } } }
创建dapperhelper帮助类
这里我们用到dapperDapper简介 - 非法关键字 - 博客园 (cnblogs.com)
ORM框架简介_orm框架是什么意思_Courage-Hu的博客-CSDN博客
实现对数据库的连接和增删改查基本方法
在common层创建一个DapperHelper类
nuget:
直接把数据库连接串替换成你自己的,内容:
using System.Data.SqlClient; using System.Data; using Dapper; namespace Project.TM.WCore.Common { /// /// Dapper帮助类 /// public class DapperHelper { #region 连接 /// /// 数据库连接串 /// public static string ConnectionString = string.Empty; /// /// 注册一个连接事件 /// public static IDbConnection? connection = null; /// /// 构造函数 /// public DapperHelper() { //ConnectionString = ConnectionProvider.GetConnection(); ConnectionString = SettingProvider.GetConnection(); //ConnectionString = ConfigurationManager.ConnectionStrings["SqlConnetion"].ConnectionString; } /// /// 获得conn对象 /// /// public IDbConnection GetConn() { return new SqlConnection(ConnectionString); } /// /// 打开conn /// /// public void OpenConn(IDbConnection conn) { conn.Open(); } /// /// 销毁conn /// /// public void DisposeConn(IDbConnection conn) { conn.Dispose(); conn.Close(); } #endregion #region 业务类 /// /// 查询. /// /// 实体类型. /// sql执行语句. /// 泛型类. public static List Query(string sql) where T : class { using (connection = new SqlConnection(ConnectionString)) { return connection.Query(sql).ToList(); } } /// /// 查询单条记录 /// /// /// /// new{...} /// public T ExecuteQuery(string sql, object? obj = null) { T result; using (connection = new SqlConnection(ConnectionString)) { result = connection.QueryFirstOrDefault(sql, obj); } return result; } /// /// 查询多条记录 /// /// /// /// new{...} /// public IEnumerable ExecuteQuerys(string sql, object? obj = null) { IEnumerable result; using (connection = new SqlConnection(ConnectionString)) { result = connection.Query(sql, obj); } return result; } /// /// 查询指定数据. /// /// 实体类型. /// sql执行语句. /// 泛型类. /// 类. public static T? Query(string sql, T t) where T : class { using (connection = new SqlConnection(ConnectionString)) { return connection.Query(sql, t).SingleOrDefault(); } } /// /// 查询的in操作. /// /// 实体类型. /// sql执行语句. /// 泛型类. public static List Query(string sql, int[] ids) where T : class { using (connection = new SqlConnection(ConnectionString)) { return connection.Query(sql, new { ids }).ToList(); } } /// /// 增删改 /// /// /// /// /// public int ExecuteNonQuery(string sql, T obj) { int result = 0; try { using (connection = new SqlConnection(ConnectionString)) { result = connection.Execute(sql, obj); } } catch { } return result; } /// /// 添加 /// /// 实体类型. /// sql执行语句. /// 传入实体类型. /// int. public static int Add(string sql) where T : class { using (connection = new SqlConnection(ConnectionString)) { return connection.Execute(sql); } } /// /// 新增后获取id /// /// /// /// /// public static int AddResultId(string sql) { int Id = 0; using (connection = new SqlConnection(ConnectionString)) { using (SqlCommand command = new SqlCommand(sql, connection as SqlConnection)) { connection.Open(); Id = Convert.ToInt32(command.ExecuteScalar()); connection.Close(); } } return Id; } /// /// 多语句操作. /// /// 实体类型. /// sql执行语句. public static void QueryMultiple(string sql) { using (connection = new SqlConnection(ConnectionString)) { var multiReader = connection.QueryMultiple(sql); multiReader.Dispose(); } } #endregion #region 事务 /// /// 开启事务 /// /// /// public IDbTransaction BeginTransaction(IDbConnection conn) { return conn.BeginTransaction(); } /// /// 提交事务 /// /// /// public void Commit(IDbTransaction tran) { tran.Commit(); } /// /// 回滚事务 /// /// /// public void Rollback(IDbTransaction tran) { tran.Rollback();//回滚 } /// /// 销毁事务 /// /// /// public void Dispose(IDbTransaction tran) { tran.Dispose();//销毁 } /// /// 查询带事务 /// /// /// /// /// /// public List? ExecuteQuerys(string sql, IDbTransaction tran) { try { return (List)connection.Query(sql, tran); } catch (Exception) { return null; } } /// /// 使用事务查询多条记录 /// /// /// /// new{...} /// public IEnumerable ExecuteQuerys(string sql, IDbTransaction tran, IDbConnection conn, object? obj = null) { IEnumerable result; result = conn.Query(sql, obj, tran); return result; } /// /// 使用事务查询单条记录 /// /// /// /// new{...} /// public T ExecuteQuery(string sql, IDbTransaction tran, IDbConnection conn, object? obj = null) { T result; result = conn.QueryFirstOrDefault(sql, obj, tran); return result; } /// /// 增删改带事务 /// /// /// /// public int ExecuteNonQuery(string sql, IDbConnection conn, IDbTransaction tran) { try { int count = conn.Execute(sql, transaction: tran); return count; } catch (Exception) { return 0; } } /// /// 新增后获取id带事务 /// /// /// /// /// /// public int AddResultId(string sql,IDbConnection conn,IDbTransaction tran) { try { return Convert.ToInt32(new SqlCommand(sql, conn as SqlConnection, tran as SqlTransaction).ExecuteScalar()); } catch (Exception) { return 0; } } #endregion /// /// 获取表名称 /// /// public static string GetTable() { var tableAttribute = (System.ComponentModel.DataAnnotations.Schema.TableAttribute)typeof(T).GetCustomAttributes(typeof(System.ComponentModel.DataAnnotations.Schema.TableAttribute), true)[0]; return tableAttribute.Name.ToString(); } } }
创建数据访问层和增删改查方法
这里创建了两个类上面是用户信息数据访问类,下面是数据访问层继承的基类
这里用基类写一些通用方法,
1.方便业务逻辑层(bll)直接调用,减少代码量
using Project.TM.WCore.Common; using Project.TM.WCore.Model.Entity.SPLC; using Project.TM.WCore.Model.Struct; using System.Data; namespace Project.TM.WCore.DAL { /// /// dal基类 /// public abstract class IBasicsDal where T : class, new() { /// /// dapper帮助类 /// public DapperHelper dapper; /// /// sql拼接结构体 /// public SqlStruct sqlStruct; /// /// 构造函数 /// protected IBasicsDal() { this.dapper = new DapperHelper(); } #region 基类虚方法,基本操作方法 /// /// 分页查询 /// /// /// /// public virtual Tuple GetPageList(int index, int size) { List list = dapper.ExecuteQuerys(DisposeSql()).ToList(); return new Tuple(list.Skip((index - 1) * size).Take(size).ToList(), list.Count); } /// /// 获取列表 /// /// public virtual List GetList() { return dapper.ExecuteQuerys(DisposeSql()).ToList(); } /// /// 根据id获取列表 /// /// /// public virtual T GetListById(int id) { return dapper.ExecuteQuery(DisposeSql(id)); } /// /// 根据参数获取列表 /// /// /// public virtual List GetListByParam(Dictionary param) { return dapper.ExecuteQuerys(DisposeSql(0, param)).ToList(); } /// /// 新增 /// /// /// public virtual bool Add(T entity) { return Convert.ToBoolean(dapper.ExecuteNonQuery(DisposeSql(0, entity: entity), entity)); } /// /// 新增返回id /// /// /// public virtual int AddResultId(T entity) { return DapperHelper.AddResultId(DisposeSql(0, entity: entity, type: 1)); } /// /// 删除 /// /// /// public virtual bool Delete(int id) { return dapper.ExecuteNonQuery(DisposeSql(id, type: 2), null) > 0 ? true : false; } /// /// 批量删除 /// /// /// public virtual bool Deletes(dynamic[] ids) { return dapper.ExecuteNonQuery(DisposeSql(0, null, null, ids, 2), null) > 0 ? true : false; } /// /// 编辑 /// /// /// public virtual bool Edit(T entity) { return dapper.ExecuteNonQuery(DisposeSql(0, null, entity, null, 3), entity) > 0 ? true : false; } /// /// 批量新增 /// /// /// public virtual bool AddList(List entityList) { foreach (var item in entityList) { var result = SqlHelper.Add(item); if (!result) return result; } return true; } #endregion #region 事务操作 /// /// 新增并返回id带事务 /// /// /// /// /// public int TranAddResultId(string Sql, IDbConnection conn, IDbTransaction tran) { int id = dapper.AddResultId(Sql, conn, tran);//新增后获取id return id; } /// /// 事务操作(未开启) /// /// 1:新增,2:删除,3:修改 /// public bool TranEntity(Dictionary tranDic) { DapperHelper dapper = new DapperHelper(); using (IDbConnection conn = dapper.GetConn()) { IDbTransaction tran = null; try { dapper.OpenConn(conn);//打开连接 tran = dapper.BeginTransaction(conn);//开启事务 //循环处理数据库操作 foreach (var item in tranDic) { switch (item.Key) { case 1://新增 dapper.ExecuteNonQuery(item.Value, conn, tran); break; case 2://删除 dapper.ExecuteNonQuery(item.Value, conn, tran); break; case 3://修改 dapper.ExecuteNonQuery(item.Value, conn, tran); break; default: break; } } dapper.Commit(tran);//提交事务 return true; } catch (Exception)//异常回滚 { dapper.Rollback(tran); return false; } finally { if (conn != null) { dapper.DisposeConn(conn);//销毁连接 } if (tran != null) { dapper.Dispose(tran);//销毁事务 } } } } /// /// 事务操作(已开启) /// /// 1:新增,2:删除,3:修改 /// public bool TranEntity(Dictionary tranDic, IDbConnection conn, IDbTransaction tran) { if (conn == null || tran == null) return false; try { //循环处理数据库操作 foreach (var item in tranDic) { dapper.ExecuteNonQuery(item.Value, conn, tran); } return true; } catch (Exception) { return false; } } #endregion /// /// 处理sql /// /// /// /// /// /// /// public string DisposeSql(int id = 0, Dictionary? param = null, T? entity = null, dynamic[]? ids = null, int type = 0) { sqlStruct = new SqlStruct(); sqlStruct.Id = id; sqlStruct.Param = param; sqlStruct.Entity = entity; sqlStruct.Ids = ids; switch (type) { case 1: sqlStruct.IsReturnId = true; break; case 2: sqlStruct.IsDelete = true; break; case 3: sqlStruct.IsUpdate = true; break; default: break; } string sql = SqlHelper.GetSql(sqlStruct); return sql; } } }
2.最后获取sql是因为dapper直接操作sql语句,每次都写sql我个人感觉比较麻烦,所以根据不同场景区分了一些通用的sql.在common创建SqlHelper:
using Project.TM.WCore.Model.Struct; using System.ComponentModel.DataAnnotations.Schema; using System.Reflection; namespace Project.TM.WCore.Common { /// /// 获取操作数据sql /// /// public static class SqlHelper where T : class, new() { /// /// 实体结构对象 /// static TableAttribute TableAttribute { get; set; } /// /// sql拼接参数结构体 /// /// /// public static string GetSql(SqlStruct sqlStruct) { TableAttribute = (TableAttribute)typeof(T).GetCustomAttributes(typeof(TableAttribute), true)[0]; string sql = string.Empty; if (sqlStruct.Id != 0 && !sqlStruct.IsDelete)//根据id查询 { sql = GetById(sqlStruct); } else if (sqlStruct.Entity != null && !sqlStruct.IsReturnId && !sqlStruct.IsUpdate)//新增 { sql = AddNew(sqlStruct); } else if (sqlStruct.Entity != null && sqlStruct.IsReturnId)//新增并返回id { sql = AddNewReturnId(sqlStruct); } else if ((sqlStruct.Id != 0 && sqlStruct.IsDelete))//删除 { sql = Delete(sqlStruct); } else if (sqlStruct.Ids != null && sqlStruct.Ids.Count() > 0)//批删 { sql = DeleteMany(sqlStruct); } else if (sqlStruct.Param?.Count > 0 && sqlStruct.IsDelete)//多条件删除 { sql = DeleteParam(sqlStruct); } else if (sqlStruct.Entity != null && sqlStruct.IsUpdate)//更新 { sql = Update(sqlStruct); } else if (sqlStruct.Param?.Count > 0&&!sqlStruct.IsDelete)//多条件查询 { sql = QueryMany(sqlStruct); } else//直接查询 { sql = $"select * from {TableAttribute.Name}"; } return sql+";"; } /// /// 多条件查询 /// /// /// private static string QueryMany(SqlStruct sqlStruct) { string sql = $"SELECT * FROM {TableAttribute.Name} WHERE 1=1"; if (sqlStruct.Param?.FirstOrDefault(p => p.Key == true).Value != null)//直接匹配 { foreach (var item in sqlStruct.Param.FirstOrDefault(p => p.Key == true).Value) { sql += $" AND {item.Key} = '{item.Value}'"; } } if (sqlStruct.Param?.FirstOrDefault(p => p.Key == false).Value != null)//模糊匹配 { sql += " AND ("; foreach (var item in sqlStruct.Param?.FirstOrDefault(p => p.Key == false).Value) { sql += $" {item.Key} LIKE '%{item.Value}%' OR"; } sql = sql.Substring(0, sql.Length - 2) + ")"; } return sql; } /// /// 更新 /// /// /// private static string Update(SqlStruct sqlStruct) { string sql = $"update {TableAttribute.Name} set"; EntityManage entityManage = GetEntity(sqlStruct.Entity); foreach (var item in entityManage.keyValuePairs) { if (item.Key == "Createtime" || item.Key == "Creator" || item.Key == "Id") { continue; } if (entityManage.ints.Contains(item.Key)) { sql += $" {item.Key} = {item.Value} ,"; } else { sql += $" {item.Key} = '{item.Value}' ,"; } } sql = sql.Substring(0, sql.Length - 1); sql += $" where id = {entityManage.keyValuePairs.Where(p => p.Key == "Id").FirstOrDefault().Value}"; return sql; } /// /// 多条件删除 /// /// /// private static string DeleteParam(SqlStruct sqlStruct) { string sql = $"Delete From {TableAttribute.Name} where 1 = 1"; if (sqlStruct.Param?.FirstOrDefault(p => p.Key == true).Value != null)//直接匹配 { foreach (var item in sqlStruct.Param.FirstOrDefault(p => p.Key == true).Value) { sql += $" AND {item.Key} = '{item.Value}'"; } } if (sqlStruct.Param?.FirstOrDefault(p => p.Key == false).Value != null)//模糊匹配 { sql += " AND ("; foreach (var item in sqlStruct.Param?.FirstOrDefault(p => p.Key == false).Value) { sql += $" {item.Key} LIKE '%{item.Value}%' OR"; } sql = sql.Substring(0, sql.Length - 2) + ")"; } return sql; } /// /// 批删 /// /// /// private static string DeleteMany(SqlStruct sqlStruct) { string sql = $"Delete {TableAttribute.Name} where "; for (int i = 0; i 0) { for (int i = 0; iUserDal继承基类IbasicDal,这样逻辑层repository实例化访问层dal就能直接访问基类的方法
创建业务层并继承于抽象层
其实抽象层和逻辑层都是基于三层架构的业务逻辑层(BLL)扩展来的,因为我们用到控制反转,所以拆分为两层,浅谈控制反转(IoC)_米碎师兄的博客-CSDN博客
同样为抽象层(以下简称IR)和逻辑层(以下简称R)创建了基类,别问,问就是省事。
1.创建IR的基类IBasicsRepository
namespace Project.TM.WCore.IRepository { /// /// 接口抽象类 /// /// public interface IBasicsRepository { /// /// 分页查 /// /// /// /// dynamic? GetPageList(int index, int size); /// /// 列表查 /// /// dynamic? GetList(); /// /// 多条件查 /// /// /// dynamic? GetListByParam(Dictionary? param); /// /// 根据id查询 /// /// /// dynamic? GetListById(int id); /// /// 新增 /// /// /// bool Add(dynamic? entity); /// /// 批增 /// /// /// bool AddList(dynamic? entityList); /// /// 删除 /// /// /// bool Delete(int id); /// /// 批删 /// /// /// bool Deletes(dynamic[]? ids); /// /// 编辑 /// /// /// bool Edit(dynamic? entity); } }2.创建IUserRepository并继承自IBasicsRepository
一般没什么特殊业务这里是不用写代码的
using Project.TM.WCore.Model.Entity.JCXX; namespace Project.TM.WCore.IRepository.JCXX { /// /// 用户抽象 /// public interface IUserRepository:IBasicsRepository { /// /// 获取验证码 /// /// /// List RegisterGet(UserEntity entity); } }3.创建R层的基类BasicsRepository并继承IR层的IBasicsRepository并实现
这里为了方便不想每次都写增删改查,直接用反射根据方法名称调用dal
using Project.TM.WCore.IRepository; using System.Reflection; namespace Project.TM.WCore.Repository { /// /// 基类 /// public abstract class BasicsRepository: IBasicsRepository { /// /// 参数 /// public Dictionary? param = null; /// /// 当前操作dal对象 /// public dynamic? thisDal = null; /// /// 新增 /// /// /// public virtual bool Add(dynamic? entity) { var thisDalType = thisDal?.GetType(); MethodInfo method = thisDalType.GetMethod("Add"); return method.Invoke(thisDal, new object[] { entity }); } public virtual bool AddList(dynamic? entityList) { throw new NotImplementedException(); } public virtual bool Delete(int id) { throw new NotImplementedException(); } public virtual bool Deletes(dynamic[]? ids) { throw new NotImplementedException(); } public virtual bool Edit(dynamic? entity) { throw new NotImplementedException(); } /// /// 查询 /// /// public virtual dynamic GetList() { var thisDalType = thisDal?.GetType(); MethodInfo method = thisDalType.GetMethod("GetList"); return method.Invoke(thisDal, new object[] { }); } public virtual dynamic GetListById(int id) { throw new NotImplementedException(); } /// /// 条件查询 /// /// /// public virtual dynamic GetListByParam(Dictionary? param) { var thisDalType = thisDal?.GetType(); MethodInfo method = thisDalType.GetMethod("GetListByParam"); return method.Invoke(thisDal, new object[] { param }); } public virtual dynamic GetPageList(int index, int size) { throw new NotImplementedException(); } } }4.创建UserRepository并继承自BasicsRepository和IUserRepository
一样没什么特殊业务这里也不用写代码,但是构造函数要初始化一下dal
using Project.TM.WCore.DAL.JCXX; using Project.TM.WCore.IRepository.JCXX; using Project.TM.WCore.Model.Entity.JCXX; namespace Project.TM.WCore.Repository.JCXX { /// /// 用户实现 /// public class UserRepository : BasicsRepository,IUserRepository { /// /// 构造函数 /// public UserRepository() { thisDal = new UserDal(); } /// /// 注册获取信息 /// /// /// /// public List RegisterGet(UserEntity entity) { return null; } } }创建Api控制器方法
1.同样创建一个基类BasicsController 和控制器LoginController
2.基类存放一些公用的变量和方法
using Microsoft.AspNetCore.Mvc; using Project.TM.WCore.IRepository.JCXX; using System.Reflection; namespace Project.TM.WCore.API.Controllers { /// /// Controller基类 /// [ApiController] [Route("api/[controller]/[action]")] public abstract class BasicsController: ControllerBase { //方案1:每个repository都在这里初始化,然后分布到对应的控制器去调用 /// /// 用户信息 /// public IUserRepository? _userRepository = null; //方案2:定义一个动态的存放repository的对象,每次调用接口给这个repository赋值 /// /// 当前控制器操作对象 /// public dynamic? thisRepostory = null; public object[]? methodParam; /// /// 必选参数 /// public Dictionary? mustParam = null; /// /// 可选参数 /// public Dictionary? minorParam = null; /// /// 参数汇总 /// public Dictionary? param = null; /// /// 多条件查询 /// /// 必选条件 /// 可选条件 /// [ApiExplorerSettings(IgnoreApi = true)] public virtual dynamic GetListByParam(Dictionary param) { // 获取 MyClass 类型 var thisRepostoryType = thisRepostory?.GetType(); MethodInfo method = thisRepostoryType.GetMethod("GetListByParam"); return method.Invoke(thisRepostory, new object[] { param }); } /// /// 动态方法操作 /// /// /// [ApiExplorerSettings(IgnoreApi = true)] public dynamic Method(string? MethodName) { var thisRepostoryType = thisRepostory?.GetType(); MethodInfo method = thisRepostoryType.GetMethod(MethodName); var methodResult = method.Invoke(thisRepostory, methodParam); methodParam = new object[] { };//清空参数 return methodResult; } } }3.登录注册方法创建
这块代码有点多,主要为了实现登录验证和Jwt验证JWT是什么_IBLiplus的博客-CSDN博客
1.依赖注入配置
1.nuget:
2.program 配置
//Autofac依赖注入 builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory()); //注册依赖 builder.Host.ConfigureContainer(containerBuilder => { containerBuilder.RegisterType().As(); //在这里写注入代码 containerBuilder.RegisterType().As();//用户 containerBuilder.RegisterType().As();//菜单 });2.Jwt配置
1.nuget
2.创建jwt实体
namespace Project.TM.WCore.Model.Entity.PubLic { public class JwtSettings { /// /// 发行人 /// public string? Issuer { get; set; } /// /// 受众人 /// public string? Audience { get; set; } /// /// 加密用的key /// public string? SecurityKey { get ; set; } /// /// 时间 /// public double Expires { get; set; } } }2.program配置
//jwt配置 var jwtSection = configuration.GetSection("JwtConfig"); JwtSettings jwtSettings = jwtSection.Get(); //添加JWT服务 builder.Services.Configure(jwtSection); JwtSettings settings = new JwtSettings(); builder.Configuration.Bind("JwtConfig", settings); builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters() { //验证发行人 ValidateIssuer = true, ValidIssuer = jwtSettings?.Issuer, 验证受众人 ValidateAudience = true, ValidAudience = jwtSettings?.Audience, // 受众 //验证token声明周期 ValidateLifetime = true, //验证签名 ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings?.SecurityKey)),// 密钥 // 是否要求Token的Claims中必须包含Expires RequireExpirationTime = true, // 允许服务器时间偏移量(默认300秒) // 即我们配置的过期时间加上这个允许偏移的时间值,才是真正过期的时间(过期时间 +偏移值) // 也可以设置为0,ClockSkew = TimeSpan.Zero ClockSkew = TimeSpan.FromSeconds(jwtSettings.Expires) }; //鉴权验证 options.Events = new JwtBearerEvents() { OnChallenge = context => { context.HandleResponse(); context.Response.StatusCode = StatusCodes.Status200OK; context.Response.ContentType = "application/json; charset=utf-8"; string resp = JsonSerializer.Serialize(new { code = 401, message = "身份证认证失败" }); context.Response.WriteAsync(resp); return Task.FromResult(0); }, OnAuthenticationFailed = context => { if (context.Exception.GetType() == typeof(SecurityTokenException)) { //JWT Token超时 context.Response.Headers.Add("act", "expired"); } return Task.CompletedTask; } }; });3.编写控制器方法
using JWT; using JWT.Algorithms; using JWT.Serializers; using Microsoft.AspNetCore.Mvc; using Microsoft.IdentityModel.Tokens; using Project.TM.WCore.Cache; using Project.TM.WCore.Common; using Project.TM.WCore.IRepository.JCXX; using Project.TM.WCore.Model.Entity.JCXX; using Project.TM.WCore.Model.Entity.PubLic; using Project.TM.WCore.Model.Enum; using Project.TM.WCore.Model.Response; using System.IdentityModel.Tokens.Jwt; using System.Net; using System.Security.Claims; using System.Text; using System.Text.Json; namespace Project.TM.WCore.API.Controllers.JCXX { /// /// 登录控制器 /// [ApiController] [Route("api/[controller]/[action]")] public class LoginController : BasicsController { /// /// 构造函数 /// /// public LoginController(IUserRepository userRepository) { if (_userRepository != null) return; _userRepository = userRepository; thisRepostory = userRepository; } /// /// 登录 允许匿名 /// /// /// [HttpPost] public IActionResult Login([FromBody] UserEntity entity) { JsonResult jsonResult;//返回结果 if (string.IsNullOrWhiteSpace(entity.UserName) || string.IsNullOrWhiteSpace(entity.Password)) { jsonResult = new JsonResult(new ReturnResponse { Code = ReturnCode.Fail, Message = "用户名或密码错误", Data = new UserResponse() }); return jsonResult; } //查询用户信息 minorParam = new Dictionary { {"UserName",entity.UserName }, {"Name",entity.UserName }, {"Contact",entity.UserName }, {"Email",entity.UserName } }; param = new Dictionary { { true,mustParam}, { false,minorParam} }; //var user = _userRepository.GetListByParam(null, minorParam); var user = GetListByParam(param); if (user == null || user?.Count 0) { return new JsonResult(new ReturnResponse { Code = ReturnCode.OK, Message = "当前手机号或邮箱已注册过,请更换" }); } UserEntity newUserEntity = new UserEntity() { UserName = entity.Contact, Password = MD5Helper.Md5Encrypt32(entity.Password), Email = entity.Email, Contact = entity.Contact, Creator = "注册", Createtime = DateTime.Now, Updatetime = DateTime.Now, Isuse = true, Sex = true }; bool result = _userRepository.Add(newUserEntity); return new JsonResult(new ReturnResponse { Code = ReturnCode.Created, Data = result }); } /// /// 发送验证码 /// /// /// [HttpPost] public IActionResult SendCode(UserEntity entity) { List userEntity = _userRepository.RegisterGet(entity); if (userEntity.Count > 0) { return new JsonResult(new ReturnResponse { Code = ReturnCode.OK, Message = "当前手机号或邮箱已注册过,请更换" }); } int returncode = PhoneNo(entity.Contact); if (returncode != 0) { return new JsonResult(new ReturnResponse { Code = ReturnCode.Created, Data = new UserResponse { Captcha = returncode } }); } return new JsonResult(new ReturnResponse { Code = ReturnCode.Fail, Message = "验证码发送失败" }); } /// /// 实现发送验证码 /// /// 手机号 /// 验证码 [ApiExplorerSettings(IgnoreApi = true)] public static int PhoneNo(string phoneno) { string account = "C38910992";//查看用户名 登录用户中心->验证码通知短信>产品总览->API接口信息->APIID string password = "fbb1c64c267100f784276d9101bdce48"; //查看密码 登录用户中心->验证码通知短信>产品总览->API接口信息->APIKEY string mobile = phoneno; Random rad = new Random(); int mobile_code = rad.Next(1000, 10000); string content = "您的验证码是:" + mobile_code + " 。请不要把验证码泄露给其他人。"; string postStrTpl = "account={0}&password={1}&mobile={2}&content={3}"; UTF8Encoding encoding = new UTF8Encoding(); byte[] postData = encoding.GetBytes(string.Format(postStrTpl, account, password, mobile, content)); HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(AuthCodeProvider.GetPostUrl()); myRequest.Method = "POST"; myRequest.ContentType = "application/x-www-form-urlencoded"; myRequest.ContentLength = postData.Length; Stream newStream = myRequest.GetRequestStream(); newStream.Write(postData, 0, postData.Length); newStream.Flush(); newStream.Close(); HttpWebResponse myResponse = (HttpWebResponse)myRequest.GetResponse(); if (myResponse.StatusCode == HttpStatusCode.OK) { StreamReader reader = new StreamReader(myResponse.GetResponseStream(), Encoding.UTF8); //code状态返回值;msg查询结果描述 string res = reader.ReadToEnd(); int len1 = res.IndexOf(""); int len2 = res.IndexOf(""); string code = res.Substring((len2 + 6), (len1 - len2 - 6)); int len3 = res.IndexOf(""); int len4 = res.IndexOf(""); string msg = res.Substring((len4 + 5), (len3 - len4 - 5)); if (msg == "提交成功") { return mobile_code; } else { return 0; } } else { return 0; } } /// /// 获取JWT.Token /// /// [ApiExplorerSettings(IgnoreApi = true)] private string GetToken(UserEntity entity) { AuthInfo authInfo = new AuthInfo() { UserName = entity.UserName, IsAdmin = true, ExpirationTime = 600 }; //密钥 const string secret = "To Live is to change the world"; //secret需要加密 IJwtAlgorithm algorithm = new HMACSHA256Algorithm(); IJsonSerializer serializer = new JsonNetSerializer(); IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder(); IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder); var token = encoder.Encode(authInfo, secret); //验证token是否为空 if (string.IsNullOrWhiteSpace(token)) return ""; return token; } [ApiExplorerSettings(IgnoreApi = true)] private string GetTokenNew(UserEntity entity) { var userData = new { Name = entity.UserName, CreatedTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") }; // 设置序列化首字母小写 JsonSerializerOptions jso = new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; string json = JsonSerializer.Serialize(userData, jso); var claims = new Claim[] { // 注意不能放入密码等敏感信息 new Claim("user", json), // 也可以增加一些JWT预定义的claim new Claim(ClaimTypes.Name, "admin") }; var jwtSet = SettingProvider.GetJwtSetting(); var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSet?.SecurityKey)); var signingCredentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); DateTime now = DateTime.Now; DateTime exp = DateTime.Now.AddSeconds(jwtSet.Expires); var token = new JwtSecurityToken( issuer: jwtSet.Issuer, // 发行人 audience: jwtSet.Audience,//受众人 //claims: claims, // 具体声明信息,注意不能放入敏感信息,这里客户端可以解密查看 notBefore: now, // 有效期开始时间 expires: exp, // 有效期结束时间 signingCredentials: signingCredentials); string str = new JwtSecurityTokenHandler().WriteToken(token); return str; } } }完成测试
成功
还没有评论,来说两句吧...