.NET圈儿的朋友们,大家好!我可太喜欢如今开源的.Net了,写代码很巴适!所以今天分享一下之前学习的一个登录小案例,代码有不足之处欢迎指正!!!

工具:采用VS Code及其插件开发,轻量化的同时减少命令行的敲写,使用VS没有冲突哈

一、通过插件创建WebApi项目

原文是个动图,可点击原文查看

二、利用插件下载项目所需要的Nuget包

三、代码编写

①新建User实体

/// <summary>
/// 登录用户实体类  继承Identiy框架提供的 IdentityUser类
/// </summary>
public class AppUser:IdentityUser
{// 自己再扩充三个字段public DateTime DateCreated { get; set; }public DateTime DateModified { get; set; }public string FullName { get; set; }
}

②新建一个上下文类

public class AppDBContext : IdentityDbContext<AppUser, IdentityRole, string>
{public AppDBContext(DbContextOptions options) : base(options){}
}

③在Startup依赖注入上下文类

services.AddDbContext<AppDBContext>(options =>
{options.UseMySql(Configuration.GetConnectionString("DefaultConnection"), MySqlServerVersion.LatestSupportedServerVersion);
});
// AddEntityFrameworkStores 用来创建 用户和密码之间的服务
services.AddIdentity<AppUser, IdentityRole>(opt => { }).AddEntityFrameworkStores<AppDBContext>();

④在终端codefirst生成数据表

dotnet ef migrations add init
dotnet ef  database update

⑤配置JWT

ConfigureServices方法里面配置服务

services.AddAuthentication(x =>
{x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>{// jwt的 key 需要设置复杂点 var key = Encoding.ASCII.GetBytes(Configuration["JWTConfig:Key"]);var issure = Configuration["JWTConfig:Issuer"];   // 发行人 var audience = Configuration["JWTConfig:Audience"];  // 受众   options.TokenValidationParameters = new TokenValidationParameters(){ValidateIssuerSigningKey = true,IssuerSigningKey = new SymmetricSecurityKey(key),ValidateIssuer = true, // 设置为True时 ValidIssure 属性设置下 不然jwt验证不会通过ValidateAudience = true, // 同上 ValidAudience 属性设置下  RequireExpirationTime = true, ValidateLifetime=true,   //  token失效缓冲时间 默认是五分钟 失效时间需要加上这五分钟缓冲//  如果 上面 ValidateIssuer  配置为false 则不需要下面两个属性ValidIssuer = issure,ValidAudience = audience,};});
// 多角色时 可以这样配置  [Authorize(Policy ="PolicyGroup")] 动作方法上可以简写
services.AddAuthorization(options =>
{options.AddPolicy("PolicyGroup", policy => policy.RequireRole("Admin", "User"));
});

Configure 方法里面使用服务

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{if (env.IsDevelopment()){app.UseDeveloperExceptionPage();app.UseSwagger();app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "SwaggerDemo v1"));}app.UseHttpsRedirection();app.UseCors("any");app.UseRouting();// 注意顺序app.UseAuthentication();app.UseAuthorization();app.UseEndpoints(endpoints =>{endpoints.MapControllers();});
}

⑥swagger配置

ConfigureServices方法里面配置服务

services.AddSwaggerGen(c =>
{c.SwaggerDoc("v1", new OpenApiInfo { Title = "SwaggerDemo", Version = "v1", Description = "Demo API for showing Swagger" });// 下面两步配置 实现 swagger 上面 “锁”c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme{In = ParameterLocation.Header,  // 位于HeaderDescription = "请于此处直接填写token 无需 Bearer然后再加空格的形式",Name = "Authorization",Type = SecuritySchemeType.Http,BearerFormat = "JWT",Scheme = "bearer"});c.AddSecurityRequirement(new OpenApiSecurityRequirement{{new OpenApiSecurityScheme{Reference=new OpenApiReference{Type=ReferenceType.SecurityScheme,Id="Bearer"}},Array.Empty<string>()}});// swagger接口注释显示 // 注意 vscode 用户需要在项目的csproj文件里面手动配置生成注释文档的属性  // 具体参见项目文件里的PropertyGroupvar fileName = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";var filePath = Path.Combine(AppContext.BaseDirectory, fileName);c.IncludeXmlComments(filePath);
});

Configure 方法里面使用服务

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{if (env.IsDevelopment()){app.UseDeveloperExceptionPage();// swagger 中间件使用app.UseSwagger();// 此处的 v1 必须与上面c.SwaggerDoc("v1") 里的一致app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "SwaggerDemo v1"));}app.UseHttpsRedirection();app.UseCors("any");app.UseRouting();// 注意顺序app.UseAuthentication();app.UseAuthorization();app.UseEndpoints(endpoints =>{endpoints.MapControllers();});
}

⑦创建UserController,并通过构造函数注入登录服务

private readonly UserManager<AppUser> _userManger;  // 用户服务
private readonly SignInManager<AppUser> _signInManger;  // 登录服务private readonly RoleManager<IdentityRole> _roleManger; // 角色服务
private readonly JWTConfig _jwtConfig;  // 配置框架将配置文件注入实体类
public UserController(ILogger<UserController> logger, UserManager<AppUser> userManager,SignInManager<AppUser> signInManager, IOptions<JWTConfig> jwtConfig, RoleManager<IdentityRole> roleManger)
{this._logger = logger;this._userManger = userManager;this._signInManger = signInManager;this._jwtConfig = jwtConfig.Value;this._roleManger = roleManger;
}

注册用户

/// <summary>
/// 用户注册
/// AddAndUpdateUserrRegisterModel 是一个Dto 接受对象
/// AllowAnonymous 不需要权限验证
/// 作者 xxxx
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
[AllowAnonymous]
[HttpPost("RegisterUser")]
public async Task<Object> RegisterUser(AddAndUpdateUserrRegisterModel model)
{try{// check  注册的时候是否包含角色if (model.Roles is null || model.Roles.Count <= 0){return await Task.FromResult(new ResponseModel(Enums.ResponseCode.Error, "角色不能为空"));}// 循环判断用户所注册的角色时候存在 创建角色的方法  AddRole()foreach (var item in model.Roles){if (!await _roleManger.RoleExistsAsync(item)){return await Task.FromResult(new ResponseModel(Enums.ResponseCode.Error, "不存在创建的角色"));}}// 生成一个用户类var user = new AppUser(){UserName = model.Email,FullName = model.FullName,Email = model.Email,DateCreated = DateTime.Now,DateModified = DateTime.UtcNow};// 注册用户 var result = await _userManger.CreateAsync(user, model.Password);if (result.Succeeded){// 注册成功后 获取临时刚刚创建的用户  var tempUser = await _userManger.FindByEmailAsync(model.Email);// 循环给创建的用户添加角色foreach (var role in model.Roles){await _userManger.AddToRoleAsync(tempUser, role); // 添加角色}return await Task.FromResult(new ResponseModel(Enums.ResponseCode.Ok, "用户被成功注册!", null));}// 创建用户失败返回return await Task.FromResult(string.Join(",", result.Errors.Select(x => x.Description).ToArray()));}catch (System.Exception ex){// 异常返回return await Task.FromResult(new ResponseModel(Enums.ResponseCode.Error, ex.Message, null));}
}

登录

/// <summary>
/// 生成Token
/// 作者 xxxx
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
private string GenarateToken(AppUser user, List<string> roles)
{var jwtTokenHandle = new JwtSecurityTokenHandler();var key = Encoding.ASCII.GetBytes(_jwtConfig.Key);// 配置 Subjectvar claims = new List<Claim>(){new Claim(JwtRegisteredClaimNames.NameId,user.Id),new Claim(JwtRegisteredClaimNames.Email,user.Email),new Claim(JwtRegisteredClaimNames.Jti,Guid.NewGuid().ToString())};foreach (var role in roles){claims.Add(new Claim(ClaimTypes.Role,role));}var tokenDescriptor = new SecurityTokenDescriptor{// 多重角色Subject=new ClaimsIdentity(claims), // 单一角色// Subject = new ClaimsIdentity(new[]// {//     new System.Security.Claims.Claim(JwtRegisteredClaimNames.NameId,user.Id),//     new System.Security.Claims.Claim(JwtRegisteredClaimNames.Email,user.Email),//     new System.Security.Claims.Claim(JwtRegisteredClaimNames.Jti,Guid.NewGuid().ToString())//     // new System.Security.Claims.Claim(ClaimTypes.Role,"role")// }),// 过期时间 12小时  Expires = DateTime.UtcNow.AddSeconds(6),SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature),Audience = _jwtConfig.Audience,  // 这里不配置 也会返回UnAuthorized Issuer = _jwtConfig.Issuer // 同上};// 创建tokenvar token = jwtTokenHandle.CreateToken(tokenDescriptor);return jwtTokenHandle.WriteToken(token);
}
/// <summary>
/// 用户登录
/// LoginModel 登录Dto接收
/// 作者 xxxx
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
[AllowAnonymous]
[HttpPost]
public async Task<object> Login(LoginModel model)
{try{if (!ModelState.IsValid){return await Task.FromResult(new ResponseModel(Enums.ResponseCode.Error, "参数不合法!", null));}var result = await _signInManger.PasswordSignInAsync(model.UserName, model.Password, false, false);if (result.Succeeded){// 成功的话获取用户var appUser = await _userManger.FindByNameAsync(model.UserName);var roles = (await _userManger.GetRolesAsync(appUser)).ToList();// await _userManger.GetRolesAsync(appUser);var user = new UserDto(appUser.FullName, appUser.Email, appUser.UserName, appUser.DateCreated, roles){// 生成Token Token = GenarateToken(appUser,roles)};return await Task.FromResult(new ResponseModel(Enums.ResponseCode.Ok, "登录成功", user));}else{return await Task.FromResult(new ResponseModel(Enums.ResponseCode.Error, "登录失败", null));}}catch (System.Exception ex){return await Task.FromResult(new ResponseModel(Enums.ResponseCode.Error, ex.Message, null));}
}

添加角色

先将上文用户登录产生的token 设置到swagger里面,然后访问只有 Admin 角色可以访问的接口

/// <summary>
/// 添加角色
/// [Authorize(Roles ="Admin")]  只有Admin角色的用户可以访问
/// 作者 xxx
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
[Authorize(Roles ="Admin")]
[HttpPost("AddRole")]
public async Task<object> AddRole(AddRoleModel model)
{try{if (model is null || string.IsNullOrWhiteSpace(model.Role)){return await Task.FromResult(new ResponseModel(Enums.ResponseCode.Error, "角色不能为空"));}// 判断【AspNetRoles】 表里  角色是否存在  if (await _roleManger.RoleExistsAsync(model.Role)){return await Task.FromResult(new ResponseModel(Enums.ResponseCode.Ok, "角色存在了"));}var role = new IdentityRole(){Name = model.Role,};// 创建角色var result = await _roleManger.CreateAsync(role);if (result.Succeeded){return await Task.FromResult(new ResponseModel(Enums.ResponseCode.Ok, "角色创建成功!"));}else{return await Task.FromResult(new ResponseModel(Enums.ResponseCode.Error, "角色创建失败!"));}}catch (System.Exception){return await Task.FromResult(new ResponseModel(Enums.ResponseCode.Error));}}

关于我们token权限在校验时出现失败怎么办?这里Asp.Net Core 5.0 新增一个接口【IAuthorizationMiddlewareResultHandler】可以处理权限验证  看下文代码展示!

/// <summary>
/// 这个是Asp.Net Core 5 新增的授权处理失败  可以直接暴露出请求上下文 省事很多啦!!!
/// 作者 xxx
/// </summary>
public class AuthorizationHandleMiddleWare : IAuthorizationMiddlewareResultHandler
{private readonly AuthorizationMiddlewareResultHandler authorizationHandleMiddleWare =new();public async Task HandleAsync(RequestDelegate next, HttpContext context, AuthorizationPolicy policy, PolicyAuthorizationResult authorizeResult){// 当 token失效或者token不存在的时候 authorizeResult.Challenged 为Trueif(authorizeResult.Challenged) {// todo 拿到上下文user对象后 此处可以check token  区分token是否是过期了var a=context.Request.Headers["Authorization"];context.Response.StatusCode=(int)HttpStatusCode.OK;await context.Response.WriteAsJsonAsync(new ResponseModel(Enums.ResponseCode.UnAuthorized,"您未授权,请检查Token是否有效!"));return ;}// 此时token 校验通过  但是访问的资源的没权限的话 authorizeResult.Forbidden 为trueif(authorizeResult.Forbidden){context.Response.StatusCode=(int)HttpStatusCode.OK;await context.Response.WriteAsJsonAsync(new ResponseModel(Enums.ResponseCode.ForBidden,"您无此权限访问哦!"));return ;}await authorizationHandleMiddleWare.HandleAsync(next,context,policy,authorizeResult);}
}

另外还需要在ConfigureService里面注册下服务

// .net 5 新增的权限验证中间件  在此处依赖注入一下  详见 AuthorizationHandleMiddleWare.cs 文件
services.AddSingleton<IAuthorizationMiddlewareResultHandler,AuthorizationHandleMiddleWare>();

以上就是一个登录的简单demo,详细代码请访问码云

作者:Jarry

原文链接:https://blog.csdn.net/qbc12345678/article/details/120758144

文中源码托管Gitee:https://gitee.com/holyace/together/tree/JarryGu_develop/framework/JwtLoginDemo

作者QQ技术交流群:346250023

实现一个登录:Mac+.NET 5+Identity+JWT+VS Code相关推荐

  1. 使用identity+jwt保护你的webapi(三)——refresh token

    前言 上一篇已经介绍了identity的注册,登录,获取jwt token,本篇来完成refresh token. 开始 开始之前先说明一下为什么需要refresh token. 虽然jwt toke ...

  2. 通用权限管理系统组件 (GPM - General Permissions Manager) 中后一个登录的把前一个登录的踢掉功能的实现...

    最近客户有需要,同一个帐户可以重复登录系统,但是后登录的账户需要把前面已经登录的账户踢掉,例如客户把电脑打开在别的电脑上然后换一个房间,或者换个办公楼想登录时就会遇到很多麻烦,遇到郁闷的情况就是死活无 ...

  3. PHP 接入 Apple 登录对 access_token/identityToken 进行 JWT 验证

    需用到 Composer 库:firebase/php-jwt,直接安装即可 composer require firebase/php-jwt 解析 JWT 头 简单示例下 UniApp 中通过 u ...

  4. python做一个登录注册界面_Python 实现简单的登录注册界面

    Python 实现简单的登录注册界面 注意:编写代码之前需要导入很重要的包 import tkinter as tk import pickle from tkinter import message ...

  5. 一个登录页面的测试用例

    转载自:http://blog.csdn.net/dml1220/article/details/44150807 具体需求: 有一个登录页面, (假如上面有2个textbox, 一个提交按钮. 请针 ...

  6. 一个登录页面的测试用例(借鉴他人的,方便查阅)

    具体需求: 有一个登录页面, (假如上面有2个textbox, 一个提交按钮. 请针对这个页面设计30个以上的testcase.) 此题的考察目的:面试者是否熟悉各种测试方法,是否有丰富的Web测试经 ...

  7. 一个登录页面的测试用例——软件测试

    具体需求: 有一个登录页面, (假如上面有2个textbox, 一个提交按钮. 请针对这个页面设计30个以上的testcase.) 此题的考察目的:面试者是否熟悉各种测试方法,是否有丰富的Web测试经 ...

  8. SilverLight学习笔记--如何在xaml文件中操作用户在后台代码定义的类(2)--示例篇:创建一个登录控件(原创)(转载本文请注明出处)...

    本文将示例如何运用前篇所写知识来建立一个用户自定义的登录控件.此控件界面非常简单,主要涉及的知识点是:   如何创建用户控件(包括对此控件的自定义事件和属性的编写,此处我们将创建一个名为LoginBo ...

  9. 积跬步,聚小流-------一个登录中的知识点

    前几天心血来潮,做了一个登录界面,发现尽管是简单的一个登录.容纳的知识点倒是不少呢. 先来看下简单的效果: 那就来简单说下.都设计了哪些知识点呢? 首先:居中:这里我使用的是绝对位置的负距离实现居中. ...

最新文章

  1. Android开发之sdcard读写数据(源代码分享)
  2. matlab模块 python,Matlab 和Python结合使用
  3. 基于Base64的图片转字符串-java和C#互通问题
  4. HTML+CSS+JavaScript复习笔记持更(八)——CSS3常用属性之列表
  5. Boost:以协程的方式实现echo服务器的实例
  6. 内存池和tcmalloc的性能比较
  7. ECMAScript 2016,2017,和2018中新增功能
  8. 提升方法-Adaboost算法
  9. java弹窗点击事件_[Java教程]jQuery的click事件在当前页弹出层窗口(不打开新页面)...
  10. 日语学习-多邻国-兴趣爱好
  11. chisel(安装)
  12. Python 进阶 之 enumerate()函数
  13. spring事件监听器系列二:@EventListener注解原理
  14. 数据库的内连接、左连接和右连接
  15. php命令行路径,命令行 – PHP命令行php.ini路径错误
  16. 研究生期间如何赚外快
  17. 计算机cpu的字母,电脑处理器后面的字母你认识几个?不认识跟我来学学(intel篇)...
  18. 特征提取与检测6-SURF特征检测
  19. Fiddler如何设置过滤?
  20. JSP电影院在线订票系统JSP电影购票系统JSP电影票预订系统JSP电影院管理jsp电影购票系统

热门文章

  1. 跨域资源共享(CORS)--跨域ajax
  2. 关于tcmalloc\malloc和new
  3. ExtJs 带分页的comboBox
  4. 50个Web设计师超便利的工具
  5. 利用Asp.net中的AJAX制作网页上自动选取开始日期及结束日期的用户自定义控件...
  6. Ubuntu 10.10, 11.04, 11.10这三个版本无法从优盘启动
  7. SQL Server数据库同步问题分享[未完,待续](一)
  8. effective C++ 条款 3:尽可能使用const
  9. 博客园电子月刊第三期出炉
  10. java调用指定浏览器_Java调用浏览器打开网页完整实例