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服务

安装Microsoft.EntityFrameworkCore.SqlServer 

示例如下:


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.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); //可以为空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.Tokens.PasswordResetTokenProvider = TokenOptions.DefaultEmailProvider;options.Tokens.EmailConfirmationTokenProvider = TokenOptions.DefaultEmailProvider;});
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");}#region 通过发送邮箱的方式重置密码/// <summary>/// 重置密码发送Token/// </summary>/// <param name="req"></param>/// <returns></returns>[HttpPost]public async Task<IActionResult> SendResetPasswordToken(SendResetPasswordTokenRequest req){string email = req.Email;var user = await _userManager.FindByEmailAsync(email);if (user == null){return NotFound($"邮箱不存在{email}");}string token = await _userManager.GeneratePasswordResetTokenAsync(user);return Ok($"向邮箱{user.Email}发送Token={token}");}/// <summary>/// 重置密码/// </summary>/// <param name="req"></param>/// <returns></returns>[HttpPost]public async Task<IActionResult> ResetPasswordToken(ResetPasswordRequest req){string userName = req.UserName;var user = await _userManager.FindByNameAsync(userName);if (user == null){return NotFound($"用户名{userName}不存在!");}var islocked = await _userManager.IsLockedOutAsync(user);if (islocked){return BadRequest("用户已锁定!");}var result = await _userManager.ResetPasswordAsync(user, req.token,req.newPassWord);if (!result.Succeeded){return BadRequest("修改失败!");}return Ok("Success");}#endregion}public record LoginRequest(string UserName, string Password);public record ChangePasswordRequest(string UserName, string oldPassword,string newPassWord);public record SendResetPasswordTokenRequest(string Email);public record ResetPasswordRequest(string UserName, string token,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.mzph.cn/news/549080.shtml

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

相关文章

在你们看来,信息网络的定级如何才能更好的发展?或者说有什么影响因素使得定级工作不好开展?

在你们看来&#xff0c;信息网络的定级如何才能更好的发展&#xff1f;或者说有什么影响因素使得定级工作不好开展&#xff1f; 可以从三个层面考虑&#xff1a; &#xff08;定级工作步骤:定级&#xff0c;备案&#xff0c;建设整改&#xff0c;等级测评&#xff0c;安全监管&…

PHP中文乱码的常见解决方法总结

PHP中文乱码是PHP开发中的常见问题之一。PHP中文乱码有时发生在网页本身&#xff0c;有些产生在于MySQL交互的过程中&#xff0c;有时与操作系统有关。下面进行一番总结。 一&#xff0e;首先是PHP网页的编码 1. php文件本身的编码与网页的编码应匹配 a. 如果欲使用gb2312编码&…

计算机网络技术期末考试复习总结

随便敲的一点复习资料 缩写题 WAN&#xff08;广域网&#xff09; LAN &#xff08;局域网&#xff09; MAN&#xff08;城域网&#xff09; PSE&#xff08;分组交换器&#xff09; PAD&#xff08;分组组装/拆卸设备&#xff09; NCC&#xff08;网络控制中心&#xff09; RT…

LYNC解决方案巡展

今天有幸参加了微软的LYNC解决方案巡展&#xff0c;也捕捉到一些镜头。和大家分享一下。 酒店入口的易拉宝。这个酒店的海鲜自助不错&#xff0c;可惜不是旋转餐厅。 微软中国及大中华区信息工作者业务群峰鹰巩的演讲。不过是纯英文的&#xff0c;没有翻译。我觉得微软在这些方…

计算机网络考试试题库-期末考试题库含答案

一、选择题(第一章 1-10&#xff1b;第二章 11-20;第三章21-35&#xff1b;第四章36-60 &#xff1b;第五章 61-73道&#xff1b;第六章 74-84道&#xff1b;第七章85-90&#xff1b;第九章91-95&#xff1b;第十章96-100) 1.下列四项内容中&#xff0c;不属于Internet&#x…

Private Inheritance(what, where)

最近在看设计模式的时候&#xff0c;看到了私有继承&#xff0c;发现对这个概念挺模糊的&#xff0c;于是一顿搜索。发现一个不错的解释。红字我做的个人笔记&#xff0c;这是要点。 原文出处&#xff1a;http://tech.163.com/05/1124/14/23B2S17F0009159Q.html 在《C箴言&…

刑法中关于计算机犯罪的规定

1.《中华人民共和国刑法》中关于计算机犯罪的规定有三个条款&#xff1a;   第285条 违反国家规定&#xff0c;侵入国家事务、国防建设、尖端科学技术领域的计算机信息系统的&#xff0c;处3年以下有期徒刑或者拘役。   第286条 违反国家规定&#xff0c;对计算机信息系统功…

巨额流量费其实可以避免

巨额流量费其实可以避免<?xml:namespace prefix o ns "urn:schemas-microsoft-com:office:office" />“史上最贵微博”一度被人们热议。说是运营商的错&#xff0c;而运营商也很无奈&#xff0c;本来这种事情就非运营商所能掌控的。其实天价流量看似可怕其实…

转帖 .Net(C#)纯GDI+绘制实时动态曲线图之二(曲线控件全部源码)

#region 曲线数据显示 #region 绘制背景网格 /// <summary> /// 刷新背景网格线&#xff0c;并返回背景图片&#xff08;背景不判断是否滚动&#xff09; /// </summary> /// <returns>返回背景图片</returns> private System.Drawing.Bitma…

SQL Server语句

SQL简介&#xff1a; 结构化查询语言&#xff0c;全拼 Structured Query Language 主要用于对数据库的操作&#xff0c;大多数据库遵循sql原则 SQL server使用的是sql的扩展集T-SQL 全拼 Transact-SQL SQL组成&#xff1a; SQL由四部分组成分别为DML DDL DQL DCL DML:数据表操…

渗透测试岗位面试题(重点:渗透测试思路)

转载自公众号&#xff1a;alisrc 本文主要是讲解遇到问题的各思路解决方法&#xff0c;不仅可做为面试题查看&#xff0c;在实操中收到思绪的阻碍也可作为参考. 1、拿到一个待检测的站&#xff0c;你觉得应该先做什么&#xff1f;1)信息收集1&#xff0c;获取域名的whois信息,获…

Mysql5.1.36 autoinstall.sh

以下脚本由杨良伟同学一手编写&#xff0c;我只是为了其他文章方便转载才放进自己的文章&#xff0c;以下有附件可以下载&#xff0c;将txt改成sh&#xff0c;赋予执行位&#xff0c;即可执行自动安装&#xff0c;忘转载者标明出处&#xff0c;谢谢。 杨良伟同学blog链接: http…

春晓JAVA的横排和竖排输出

public class ChunXiao {public static void main(String[] args) {String a[][] { { "春", "眠", "不", "觉", "晓", "&#xff0c;" }, { "处", "处", "闻", "啼", &…

Android BroadcastReceiver应用

1. 创建Receiver&#xff0c;两种方式&#xff0c;动态和静态&#xff1a; &#xff08;1&#xff09;静态注册&#xff1a; 首先自定义个Receiver&#xff0c; publicclassMyReceiver extendsBroadcastReceiver { Override publicvoidonReceive(Context context, Intent…

JAVA “百鸡问题”:鸡翁一,值钱五,鸡母一,值钱三,鸡雏三,值钱一。百钱买百鸡,问鸡翁、鸡母、鸡雏各几何?

public class BaiYuanBaiJi {public static void main(String[] args) {int x 0, y 0, z 0;//各种鸡的数量 xyz100(只) 5x3yz/3100(元)for (x 0; x < 20; x) {//全部买公鸡&#xff0c;最大是20只for (y 0; y < 33; y) {//全部买母鸡&#xff0c;最大是33只z 100…

mssql 2008恢复xp_cmdshell

EXEC sp_configure show advanced options, 1;RECONFIGURE;EXEC sp_configure xp_cmdshell, 1;RECONFIGURE; 关闭一样.只是将上面的后面的那个"1"改成"0"就可以了. EXEC sp_configure show advanced options, 1;RECONFIGURE;EXEC sp_configure xp_cmdshell…

用数组保存每个月份的天数,输出每个月有多少天。输入一个年份,输出该年份每个月的天数(提醒:闰年二月份多一天)

2、用数组保存每个月份的天数&#xff0c;输出每个月有多少天。 输入一个年份&#xff0c;输出该年份每个月的天数&#xff08;提醒&#xff1a;闰年二月份多一天&#xff09; import java.util.Scanner;public class TianShu {public static void main(String[] args) {int a[…

使用Symantec Altiris 来监控 Dell 服务器 的 硬件

最近一直在折腾DMC 监控 Dell 服务器&#xff0c; Altiris 6 对Dell的监控策略会丰富很多 &#xff0c;到了 7 严重缩水&#xff0c;6的策略又不能转化成7 ~~比较郁闷~~ 唯有自己去写不过最算给我写完了大部分常用的~~ 主要是 电源、电压、风扇、温度、处理器、内存、电池 等等…

从键盘输入四个数保存在数组中,找出最大、最小值 java

import java.util.Scanner;public class ZuiDaZuiXiao {public static void main(String[] args) {int a[] new int[4];Scanner s new Scanner(System.in);System.out.println("请输入4个数");//赋值数组for (int i 0; i < a.length; i) {a[i] s.nextInt();}/…

Technical Tcode List

Basis 需要知道的 SAP R/3 Technical Transaction Code List CCMS MENU (Transaction SRZL) Control Monitoring ------------------ RZ02 System Monitor AL01 SAP Alert Monitor RZ01 Job Scheduling Monitor RZ20 CCMS Alert Monitor (v4) RZ03 Presentation, Control SAP …