NET中使用Identity+CodeFirst+Jwt实现登录、鉴权

目录

前言

一、创建上下文类

1.自定义MyContext上下文类继承IdentityDbContext

2.在Program中添加AddDbContext服务

二、使用Migration数据迁移

1.在控制台中 依次使用add-migration 、updatebase 命令 

2.如何修改表名 

3.如何自定义字段

三、使用Identity实现登录、修改密码

1.在Program中 添加AddIdentityCore服务、AddRoleManager、AddUserManager配置

2.在控制器注入UserManager、RoleManager服务

四、使用JWT实现权限验证

1.在启动类Program.cs中配置Swagger可以输入身份验证方式

2.配置类信息、AddAuthentication服务

3.在登录的接口中返回token

4.在需要鉴权的接口加上 [Authorize]

总结


前言

identity

ASP.NET Core提供了标识(identity)框架,它采用RBAC(role-based access control,基于角色的访问控制)策略,内置了对用户、角色等表的管理及相关的接口,从而简化了系统的开发。

CodeFirst

先创建实体类,再通过实体类反向的创建数据库和表结构

什么是JWT?
JSON WEB Token,是一种基于JSON的、用于在网络上声明某种主张的令牌(token)

JWT组成
JWT通常由三部分组成: 头信息(header), 消息体(payload)和签名(signature)

头信息指定了该JWT使用的签名算法,HS256 表示使用了 HMAC-SHA256 来生成签名。
消息体包含了JWT的意图
未签名的令牌由base64url编码的头信息和消息体拼接而成(使用"."分隔),签名则通过私有的key计算而成。
最后在未签名的令牌尾部拼接上base64url编码的签名(同样使用"."分隔)就是JWT了
典型的JWT的格式:xxxxx.yyyyy.zzzzz


创建上下文类

  安装Microsoft.EntityFrameworkCore

  安装Microsoft.AspNetCore.Identity.EntityFrameworkCore 

1.自定义MyContext上下文类继承IdentityDbContext

示例如下:

    public class MyContext : IdentityDbContext{public MyContext(DbContextOptions<MyContext> options) : base(options){}protected override void OnModelCreating(ModelBuilder modelBuilder){base.OnModelCreating(modelBuilder);      }}

2.在Program中添加AddDbContext服务

示例如下:


builder.Services.AddDbContext<MyContext>(options =>
{var connectionStr = builder.Configuration.GetConnectionString("SqlServer:Connection");options.UseSqlServer(connectionStr);
});

在配置文件中appsettings.json配置连接字符串

  "ConnectionStrings": {"sqlserver": {"Connection": "Server=服务器名称;User Id=账号;Password=密码;Database=数据库;MultipleActiveResultSets=true;Encrypt=True;TrustServerCertificate=True;"}}

二、使用Migration数据迁移

安装Microsoft.EntityFrameworkCore.SqlServer 

安装Microsoft.EntityFrameworkCore.Tools 

1.在控制台中 依次使用add-migration 、updatebase 命令 

如图所示

执行成功后 去数据库看数据库已经建立好了

效果如下:

2.如何修改表名 

生成的表都默认是带有AspNet 觉得不喜欢,那怎么修改呢

使用 FluentAPI配置

示例如下:

public class UserConfig : IEntityTypeConfiguration<IdentityUser>{public void Configure(EntityTypeBuilder<IdentityUser> builder){builder.ToTable("User");}}public class RoleConfig : IEntityTypeConfiguration<IdentityRole>{public void Configure(EntityTypeBuilder<IdentityRole> builder){builder.ToTable("Role");}}public class UserRoleConfig : IEntityTypeConfiguration<IdentityUserRole<string>>{public void Configure(EntityTypeBuilder<IdentityUserRole<string>> builder){builder.ToTable("UserRole");}}

 在OnModelCreating方法中加入

// 反射中找项目下所有 继承IEntityTypeConfiguration的配置modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly);

再次执行add-migration 、updatebata 命令 

再去数据库查看

已经成功修改我们想要的表名了

3.如何自定义字段

比如我想在用户表中添加年龄字段,创建新的用户类去继承IdentityUser类

示例如下:

    public class User: IdentityUser{/// <summary>///   年龄/// </summary>public int? Age { get; set; }/// <summary>/// 备注/// </summary>public string ReMark { get; set; }}

在UserConfig类中修改成User

        public class UserConfig : IEntityTypeConfiguration<User>{public void Configure(EntityTypeBuilder<User> builder){builder.Property(x => x.Id).HasColumnOrder(1);//字段排序builder.Property(x => x.Age).IsRequired(false); //指定类型int ,可以为空builder.Property(x => x.ReMark).HasMaxLength(200).IsRequired(false); //指定长度 ,可以为空builder.ToTable("User");}}

注意:上下文MyContext:IdentityDbContext需要修改成MyContext:IdentityDbContext<User>

这时候 再去执行migration命令,再去看数据库,已经加上了

效果如下: 

三、使用Identity实现登录、修改密码

1.在Program中 添加AddIdentityCore服务、AddRoleManager、AddUserManager配置

示例如下: 


builder.Services.AddIdentityCore<User>(options =>
{//配置用户名options.User = new UserOptions{RequireUniqueEmail = false, //要求Email唯一//AllowedUserNameCharacters = "abcdefgABCDEFG123456789" //允许的用户名字符,默认是 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+};//配置密码options.Password = new PasswordOptions{RequiredLength = 6, //要求密码最小长度,默认是 6 个字符RequireDigit = true, //要求有数字RequiredUniqueChars = 1, //要求至少要出现的字母数RequireLowercase = false, //要求小写字母RequireNonAlphanumeric = false, //要求特殊字符RequireUppercase = false //要求大写字母};//锁定账户options.Lockout = new LockoutOptions{AllowedForNewUsers = true, // 新用户锁定账户DefaultLockoutTimeSpan = TimeSpan.FromMinutes(1), //锁定时长,默认是 5 分钟MaxFailedAccessAttempts = 3 //登录错误最大尝试次数,默认 5 次};//数据库存储options.Stores = new StoreOptions{MaxLengthForKeys = 128, // 主键的最大长度 ,如果不设置,主键则是 max 的字符串长度ProtectPersonalData = false //保护用户数据,要求实现 IProtectedUserStore 接口}; //令牌配置options.Tokens = new TokenOptions{AuthenticatorIssuer = "Identity", //认证的消费者AuthenticatorTokenProvider = "MyAuthenticatorTokenProvider", //认证令牌的提供者ChangeEmailTokenProvider = "MyChangeEmailTokenProvider", //更换邮箱的令牌提供者ChangePhoneNumberTokenProvider = "MyChangePhoneNumberTokenProvider", //更换手机号的令牌提供者EmailConfirmationTokenProvider = "MyEmailConfirmationTokenProvider", //验证邮箱的令牌提供者PasswordResetTokenProvider = "MyPasswordResetTokenProvider", //重置密码的令牌提供者ProviderMap = new Dictionary<string, TokenProviderDescriptor>()};//声明配置options.ClaimsIdentity = new ClaimsIdentityOptions{RoleClaimType = "IdentityRole",UserIdClaimType = "IdentityId",SecurityStampClaimType = "SecurityStamp",UserNameClaimType = "IdentityName"};//在登录的时候,如果手机号或邮箱没有激活/确认,则无法登录。options.SignIn = new SignInOptions{RequireConfirmedEmail = true, //要求激活邮箱RequireConfirmedPhoneNumber = true //要求激活手机号};
});
var idBuilder = new IdentityBuilder(typeof(User), typeof(IdentityRole), builder.Services);
idBuilder.AddEntityFrameworkStores<MyContext>().AddDefaultTokenProviders().AddRoleManager<RoleManager<IdentityRole>>().AddUserManager<UserManager<User>>();

2.在控制器注入UserManager、RoleManager服务

示例如下: 

    [ApiController][Route("[controller]/[action]")]public class UserController : ControllerBase{private readonly UserManager<User> _userManager;public UserController(UserManager<User> userManager){_userManager = userManager;}/// <summary>/// 创建用户/// </summary>/// <returns></returns>[HttpPost]public async Task<IActionResult> CreateUser(LoginRequest loginRequest){    User user = await _userManager.FindByNameAsync(loginRequest.UserName);if (user == null){user = new User{UserName = loginRequest.UserName};var result = await _userManager.CreateAsync(user, loginRequest.Password);if (!result.Succeeded){return BadRequest(result.Errors);}         }return Ok();}/// <summary>/// 登录/// </summary>/// <param name="loginRequest"></param>/// <returns></returns>[HttpPost]public async Task<IActionResult> Login(LoginRequest loginRequest){string userName = loginRequest.UserName;string password = loginRequest.Password;var user = await _userManager.FindByNameAsync(userName);if (user == null){return NotFound($"用户名{userName}不存在!");}var islocked = await _userManager.IsLockedOutAsync(user);if (islocked){return BadRequest("用户已锁定!");}var success = await _userManager.CheckPasswordAsync(user, password);if (success){return Ok();}else{var r = await _userManager.AccessFailedAsync(user);if (!r.Succeeded){return BadRequest("访问失败信息写入错误!");}else{return BadRequest("失败!");}}}/// <summary>/// 修改密码/// </summary>/// <param name="req"></param>/// <returns></returns>[HttpPost]public async Task<IActionResult> ChangePassword(ChangePasswordRequest req){    var user = await _userManager.FindByNameAsync(req.UserName);if (user == null){return NotFound($"用户名{req.UserName}不存在!");}var result = await _userManager.ChangePasswordAsync(user,req.oldPassword,req.newPassWord);if (!result.Succeeded){return BadRequest("修改失败!");}return Ok("Success");}}public record LoginRequest(string UserName, string Password);public record ChangePasswordRequest(string UserName, string oldPassword,string newPassWord);

四、使用JWT实现权限验证


安装Microsoft.AspNetCore.Authentication.JwtBearer

1.在启动类Program.cs中配置Swagger可以输入身份验证方式

示例如下: 

builder.Services.AddSwaggerGen(options =>
{options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme{Description = "请输入token,格式为 Bearer xxxxxxxx(注意中间必须有空格)",Name = "Authorization",//jwt默认的参数名称In = ParameterLocation.Header,//jwt默认存放Authorization信息的位置(请求头中)Type = SecuritySchemeType.ApiKey,BearerFormat = "JWT",Scheme = "Bearer"});//添加安全要求options.AddSecurityRequirement(new OpenApiSecurityRequirement {{new OpenApiSecurityScheme{Reference =new OpenApiReference{Type = ReferenceType.SecurityScheme,Id ="Bearer"}},new string[]{ }}});});

2.配置类信息、AddAuthentication服务

示例如下:

    public class JWTOptions{/// <summary>/// 颁发者        /// </summary>public string Issuer { get; set; }/// <summary>/// 接收者       /// </summary>public string Audience { get; set; } /// <summary>/// 密钥/// </summary>public string SigningKey { get; set; }/// <summary>/// 过期时间/// </summary>public int ExpireSeconds { get; set; }}

在配置文件appsettings.json中加入以下信息

  "JWT": {"Issuer": "我是小小鱼","Audience": "我是小小鱼","SigningKey": "fasdfad&9045dafz222#fadpio@0232","ExpireSeconds": "3600"}

在添加AddAuthentication服务

builder.Services.Configure<JWTOptions>(builder.Configuration.GetSection("JWT"));
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(x =>
{var jwtOpt = builder.Configuration.GetSection("JWT").Get<JWTOptions>();byte[] keyBytes = Encoding.UTF8.GetBytes(jwtOpt.SigningKey);var secKey = new SymmetricSecurityKey(keyBytes);x.TokenValidationParameters = new(){ValidateIssuer = true,//是否验证IssuerValidateAudience = true,//是否验证AudienceValidateIssuerSigningKey = true,//是否验证SecurityKeyValidIssuer = jwtOpt.Issuer,ValidAudience=jwtOpt.Audience,IssuerSigningKey = secKey,ValidateLifetime = true, //是否验证失效时间ClockSkew = TimeSpan.FromSeconds(4)};
});

 创建一个Jwt辅助类

  public class JwtHelper{public static string BuildToken(IEnumerable<Claim> claims, JWTOptions options){DateTime expires = DateTime.Now.AddSeconds(options.ExpireSeconds);byte[] keyBytes = Encoding.UTF8.GetBytes(options.SigningKey);var secKey = new SymmetricSecurityKey(keyBytes);var credentials = new SigningCredentials(secKey,SecurityAlgorithms.HmacSha256Signature);var tokenDescriptor = new JwtSecurityToken(options.Issuer,options.Audience,expires: expires,signingCredentials: credentials, claims: claims);return new JwtSecurityTokenHandler().WriteToken(tokenDescriptor);}}

3.在登录的接口中返回token

示例如下:

        /// <summary>/// 登录/// </summary>/// <param name="loginRequest"></param>/// <returns></returns>[HttpPost]public async Task<IActionResult> Login(LoginRequest loginRequest,[FromServices] IOptions<JWTOptions> jwtOptions){string userName = loginRequest.UserName;string password = loginRequest.Password;var user = await _userManager.FindByNameAsync(userName);if (user == null){return NotFound($"用户名{userName}不存在!");}var islocked = await _userManager.IsLockedOutAsync(user);if (islocked){return BadRequest("用户已锁定!");}var success = await _userManager.CheckPasswordAsync(user, password);if (success){var claims = new List<Claim>();claims.Add(new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()));claims.Add(new Claim(ClaimTypes.Name, user.UserName));var roles = await _userManager.GetRolesAsync(user);foreach (string role in roles){claims.Add(new Claim(ClaimTypes.Role, role));}string Token = JwtHelper.BuildToken(claims, jwtOptions.Value);return Ok(Token);}else{var r = await _userManager.AccessFailedAsync(user);if (!r.Succeeded){return BadRequest("访问失败信息写入错误!");}else{return BadRequest("失败!");}}}

效果如下

4.在需要鉴权的接口加上 [Authorize]

示例如下:

        /// <summary>/// 获取用户信息/// </summary>/// <returns></returns>[HttpPost][Authorize]public async Task<IActionResult> GetUser() {var claimsPrincipal = this.HttpContext.User;var name = claimsPrincipal.Claims.FirstOrDefault(r => r.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name")?.Value;var user = await _userManager.FindByNameAsync(name);if (user == null){return BadRequest("token有误");}return Ok($"获取用户名:{user.UserName},邮箱:{user.Email}");}

运行效果


总结

以上简单用Identity框架在通过migration命令建库建表,再使用 FluentAPI配置表名、字段,用dentity框架封装的UserManager实现登录、修改密码,以及通过token实现鉴权

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/297123.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2024年起重机司机(限门式起重机)证考试题库及起重机司机(限门式起重机)试题解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年起重机司机(限门式起重机)证考试题库及起重机司机(限门式起重机)试题解析是安全生产模拟考试一点通结合&#xff08;安监局&#xff09;特种作业人员操作证考试大纲和&#xff08;质检局&#xff09;特种设备作…

MATLAB - 估计滤波器(Estimation Filters)

系列文章目录 前言 本篇文章翻译自官网&#xff0c;部分下标有问题&#xff0c;请自行分辨。 一、背景介绍 1.1 估算系统 对于许多自主系统&#xff08;autonomous systems&#xff09;来说&#xff0c;了解系统状态&#xff08;system state&#xff09;是设计任何应用的先决…

运行时和编译时使用的so库不同是否影响可执行文件执行

引子 近日遇到如下问题: 1.如果可执行文件依赖的so库在编译和执行阶段使用的名字一样&#xff0c;但是内容不一样&#xff0c;比如运行时相比于编译时在so库里增加了几个api定义&#xff0c;so库还可以正常使用吗&#xff1f; 2.如果可执行文件依赖的so库在编译和执行阶段使用的…

Python与COM组件在Zemax中的高效交互指南

更多Python学习内容&#xff1a;ipengtao.com 大家好&#xff0c;我是彭涛&#xff0c;今天为大家分享 Python与COM组件在Zemax中的高效交互指南。全文4600字&#xff0c;阅读大约15分钟 Zemax是一款用于光学设计和仿真的强大工具&#xff0c;而Python作为一种通用性语言&#…

前端扫盲:什么是API网关?为什么它有用?

API 通常被称为应用程序从后端服务访问数据和业务逻辑的前门。API 本质上是一个软件向其他人或程序提供的接口&#xff0c;允许他们与该软件进行交互。 在创建 API 时&#xff0c;需要选择编程语言(Java、Python、PHP 等)来编写 API 逻辑&#xff0c;还需要将 API 部署到服务器…

3.认识HTML

一、HTML是什么&#xff1f; 超&#xff1a;超链接 二、W3C制定了HTML规范 2014年HTML5正式发布 三、HTML初体验 四、老师常用网站

WorkPlus Meet实现企业局域网视频会议的领先解决方案

在当今全球化的商业环境中&#xff0c;视频会议已成为企业高效沟通协作的重要工具。而在企业内部&#xff0c;局域网视频会议系统则具备更高的安全性和稳定性。WorkPlus Meet作为一种全新选择的局域网视频会议系统&#xff0c;以其卓越的性能和领先的技术&#xff0c;为企业打造…

29.Java程序设计-基于Springboot的幼儿园管理系统的设计与实现

1. 引言 背景介绍&#xff1a;幼儿园管理系统的必要性和重要性。研究目的&#xff1a;设计一个基于Spring Boot的系统以优化幼儿园管理流程。论文结构概览。 2. 需求分析 用户需求&#xff1a;不同用户&#xff08;管理员、老师、家长&#xff09;的需求分析。功能需求&…

Linux入门攻坚——9、Linux程序包管理-1

Linux程序包管理&#xff08;1&#xff09; 如何在Linux上安装、查询、卸载、升级程序&#xff08;对于使用者很重要的知识点&#xff0c;使用Linux就是要使用其上的程序&#xff0c;如果程序都安装不上&#xff0c;谈何使用&#xff09; 程序从源代码到最终能够执行的代码需…

RabbmitMQ基础

RabbmitMQ基础 1.1 什么是MQ MQ(Message Queue)&#xff0c;从字面意思看&#xff0c;本质是个队列&#xff0c;FIFO先入先出&#xff0c;队列中存放的是message。是一种跨进程的通信机制&#xff0c;用于上下游传递消息。在互联网架构中&#xff0c;MQ是一种非常常见的上下游…

使用Open3D实现3D激光雷达可视化:以自动驾驶的2DKITTI深度框架为例(下篇)

原创 | 文 BFT机器人 【原文链接】使用Open3D实现3D激光雷达可视化&#xff1a;以自动驾驶的2DKITTI深度框架为例&#xff08;上篇&#xff09; 05 Open3D可视化工具 多功能且高效的3D数据处理&#xff1a;Open3D是一个全面的开源库&#xff0c;为3D数据处理提供强大的解决方…

MOSFET管驱动设计细节,波形分析

MOSFET管驱动设计细节,波形分析 Chapter1 MOSFET管驱动设计细节,波形分析MOSFET驱动芯片的内部结构MOS驱动电路设计需要注意的地方MOS管驱动电路参考MOS管驱动电路的布线设计常见的MOS管驱动波形高频振铃严重的毁容方波又胖又圆的肥猪波打肿脸充正弦的生于方波他们家的三角波大…