使用identity+jwt保护你的webapi(二)——获取jwt token

前言

上一篇已经介绍了identity在web api中的基本配置,本篇来完成用户的注册,登录,获取jwt token。

开始

开始之前先配置一下jwt相关服务。

配置JWT

首先NuGet安装包:

<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="5.0.10" />

appsettings.json中添加jwt配置:

"JwtSettings": {"SecurityKey": "qP1yR9qH2xS0vW2lA3gI4nF0zA7fA3hB","ExpiresIn": "00:10:00"
}

为了方便,新建一个配置类JwtSettings

public class JwtSettings
{public string SecurityKey { get; set; }public TimeSpan ExpiresIn { get; set; }
}

在Startup中配置jwt:

public void ConfigureServices(IServiceCollection services)
{//省略......var jwtSettings = Configuration.GetSection(nameof(JwtSettings)).Get<JwtSettings>();services.AddSingleton(jwtSettings);var tokenValidationParameters = new TokenValidationParameters{ValidateIssuer = false,ValidateAudience = false,ValidateIssuerSigningKey = true,IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(jwtSettings.SecurityKey)),ClockSkew = TimeSpan.Zero,};services.AddAuthentication(options =>{options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;}).AddJwtBearer(options => { options.TokenValidationParameters = tokenValidationParameters; });
}

最后别忘了UseAuthentication

app.UseAuthentication(); // add
app.UseAuthorization();

结构搭建

下面把项目基本结构搭建好,做好接口,后面实现:

dc1869c6d1b78cd493e5ada0f66d355c.png

以下是各个类的定义:

// 用户注册请求参数
public class RegisterRequest
{public string UserName { get; set; }public string Password { get; set; }public string Address { get; set; }
}
// 用户登录请求参数
public class LoginRequest
{public string UserName { get; set; }public string Password { get; set; }
}
// 注册 登录 成功后返回 token
public class TokenResponse
{[JsonPropertyName("access_token")] public string AccessToken { get; set; }[JsonPropertyName("token_type")] public string TokenType { get; set; }
}
// 登录 注册 失败时返回错误信息
public class FailedResponse
{public IEnumerable<string> Errors { get; set; }
}
// IUserService 接口
public interface IUserService
{Task<TokenResult> RegisterAsync(string username, string password, string address);Task<TokenResult> LoginAsync(string username, string password);
}
// UserService 实现
public class UserService : IUserService
{public Task<TokenResult> RegisterAsync(string username, string password, string address){throw new System.NotImplementedException();}public Task<TokenResult> LoginAsync(string username, string password){throw new System.NotImplementedException();}
}
// TokenResult 定义
public class TokenResult
{public bool Success => Errors == null || !Errors.Any();public IEnumerable<string> Errors { get; set; }public string AccessToken { get; set; }public string TokenType { get; set; }
}

最后是UserController

[Route("api/[controller]")]
[ApiController]
public class UserController : ControllerBase
{private readonly IUserService _userService;public UserController(IUserService userService){_userService = userService;}[HttpPost("Register")]public async Task<IActionResult> Register(RegisterRequest request){var result = await _userService.RegisterAsync(request.UserName, request.Password, request.Address);if (!result.Success){return BadRequest(new FailedResponse(){Errors = result.Errors});}return Ok(new TokenResponse{AccessToken = result.AccessToken,TokenType = result.TokenType});}[HttpPost("Login")]public async Task<IActionResult> Login(LoginRequest request){var result = await _userService.LoginAsync(request.UserName, request.Password);if (!result.Success){return Unauthorized(new FailedResponse(){Errors = result.Errors});}return Ok(new TokenResponse{AccessToken = result.AccessToken,TokenType = result.TokenType});}
}

service实现

上面已经做好了基本的结构,接下来就是实现UserService中的RegisterAsyncLoginAsync方法了。这里主要用到identity中的UserManager,UserManager封装了很多用户操作的现成方法。

UserService中先做一个私有方法,根据user创建jwt token;用户注册,登录成功后调用此方法得到token返回即可:

private TokenResult GenerateJwtToken(AppUser user)
{var key = Encoding.ASCII.GetBytes(_jwtSettings.SecurityKey);var tokenDescriptor = new SecurityTokenDescriptor{Subject = new ClaimsIdentity(new[]{new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString("N")),new Claim(JwtRegisteredClaimNames.Sub, user.Id.ToString())}),IssuedAt = DateTime.UtcNow,NotBefore = DateTime.UtcNow,Expires = DateTime.UtcNow.Add(_jwtSettings.ExpiresIn),SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key),SecurityAlgorithms.HmacSha256Signature)};var jwtTokenHandler = new JwtSecurityTokenHandler();var securityToken = jwtTokenHandler.CreateToken(tokenDescriptor);var token = jwtTokenHandler.WriteToken(securityToken);return new TokenResult(){AccessToken = token,TokenType = "Bearer"};
}

注册方法实现:

public async Task<TokenResult> RegisterAsync(string username, string password, string address)
{var existingUser = await _userManager.FindByNameAsync(username);if (existingUser != null){return new TokenResult(){Errors = new[] {"user already exists!"}, //用户已存在};}var newUser = new AppUser() {UserName = username, Address = address};var isCreated = await _userManager.CreateAsync(newUser, password);if (!isCreated.Succeeded){return new TokenResult(){Errors = isCreated.Errors.Select(p => p.Description)};}return GenerateJwtToken(newUser);
}

登录方法实现:

public async Task<TokenResult> LoginAsync(string username, string password)
{var existingUser = await _userManager.FindByNameAsync(username);if (existingUser == null){return new TokenResult(){Errors = new[] {"user does not exist!"}, //用户不存在};}var isCorrect = await _userManager.CheckPasswordAsync(existingUser, password);if (!isCorrect){return new TokenResult(){Errors = new[] {"wrong user name or password!"}, //用户名或密码错误};}return GenerateJwtToken(existingUser);
}

最后,别忘了注册UserService

services.AddScoped<IUserService, UserService>();

swagger配置

为了方便测试,可以配置一下swagger

NuGet安装包:

<PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />

ConfigureServices:

services.AddSwaggerGen(c =>
{c.SwaggerDoc("v1", new OpenApiInfo{Title = "Sample.Api",Version = "v1",Description = "Sample.Api Swagger Doc"});c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme{Description = "Input the JWT like: Bearer {your token}",Name = "Authorization",In = ParameterLocation.Header,Type = SecuritySchemeType.ApiKey,BearerFormat = "JWT",Scheme = "Bearer"});c.AddSecurityRequirement(new OpenApiSecurityRequirement{{new OpenApiSecurityScheme{Reference = new OpenApiReference{Type = ReferenceType.SecurityScheme,Id = "Bearer"}},Array.Empty<string>()}});
});
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Sample.Api v1"));

测试一下

401adbb98fbbab91efd054ed114bb761.png

随便输入abc进行注册,返回了一些密码规则的错误:

8339ef1b0e4f1c18967028f215cf0590.png

这个规则在注册identity服务时可以配置:

services.AddIdentityCore<AppUser>(options =>
{options.Password.RequireDigit = true;options.Password.RequireLowercase = false;options.Password.RequireUppercase = false;options.Password.RequireNonAlphanumeric = false;
}).AddEntityFrameworkStores<AppDbContext>();

identityOptions还支持一些其他配置。

下面注册成功后返回了token:

aa3184592461c64e729c56c94dbf4c36.png

使用刚刚注册的账号测试登录,也没有问题:

6930c0b3fb5f177553428ffc08b67395.png

最后

本篇完成了identity的登录,注册,获取token,下一篇将介绍如何使用refresh token。

参考:

ASP.NET Core 简介 Identity | Microsoft Docs[1]

Mohamad Lawand - DEV Community[2]

参考资料

[1]

ASP.NET Core 简介 Identity | Microsoft Docs: https://docs.microsoft.com/zh-cn/aspnet/core/security/authentication/identity?view=aspnetcore-5.0&tabs=visual-studio

[2]

Mohamad Lawand - DEV Community: https://dev.to/moe23/comments

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

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

相关文章

假如,绿茶婊的目标变成女生......

1 假如绿茶的目标是女生▼2 也不知道我爹今晚回去要迎接怎样的狂风暴雨▼3 这撞衫撞得有点尴尬▼4 我是一个小胖子没事玩玩小肚子▼5 看起来也不傻可能就是单纯的有猫病▼6 在严肃场合努力憋笑的我▼7 妈妈&#xff1a;叫你吃饭不吃饭&#xff01;三请四请才肯来&#x…

使用Mutex實現單一程式執行個體的注意事項(转)

相信大家都知道在.NET程式中若要實現單一程式執行個體&#xff0c;一般來說有幾種方法&#xff0c;像是去判斷是否已經有開啟的Process是相同的程式、用Mutex與Semaphore之類的技術來判斷是否程式正在開啟。但是很多網路上的文章都忽略了在用Mutex實現單一程式執行個體時&#…

docker 启动mysql root用户_Docker-Compose搭建Wordpress博客系统

环境&#xff1a;CentOS 7.5Docker 20.10.2Docker-Compose 1.25.5[rootlocalhost ~]# cat /etc/redhat-releaseCentOS Linux release 7.5.1804 (Core)[rootlocalhost ~]# docker version # Docker版本Client: Docker Engine - Community Version: 20.10.2…

理解元数据

元数据&#xff0c;metadata&#xff0c;最本质的解读&#xff1a;data about data&#xff0c;info about information. 1.&#xff08;针对dotnet&#xff09;反射是一种在运行时获取和使用元数据的技术。其本质在于元数据。对应一个程序集的描述是Assembly类&#xff0c;对应…

python函数参数类型检查_Python中实现参数类型检查的简单方法

Python是一门弱类型语言&#xff0c;很多从C/C转过来的朋友起初不是很适应。比如&#xff0c;在声明一个函数时&#xff0c;不能指定参数的类型。用C做类比&#xff0c;那就是所有参数都是void*类型&#xff01;void类型强制转换在C中被广泛地认为是个坏习惯&#xff0c;不到万…

开机的时候重新设置密linux管理员的密码

1. 在出现grub画面时&#xff0c;用上下键选中你平时启动linux的那一项&#xff0c;然后按e键2. 再次用上下键选中你平时启动linux的那一项(类似于kernel/boot/vmlinuz-2.4.18-14 ro rootLABEL/)&#xff0c;然后按e键3. 修改你现在见到的命令行&#xff0c;加入single&#xf…

跪着看完这14个机械动图

全世界只有3.14 % 的人关注了爆炸吧知识神奇的机械原理动态GIF图&#xff0c;很有意思&#xff0c;或许你能学到点什么&#xff01;↑↑时间书写机器↑↑↑↑鸡尾酒制作机↑↑↑↑移树机↑↑↑↑扔球机&#xff08;用于陪狗玩&#xff09;↑↑↑↑甜甜圈抓取机↑↑↑↑玻璃瓶加…

再来说说我喜欢的 Dotnet 5.0 C# 9

上次写完 C# 10&#xff0c;有兄弟在后台问 C# 9&#xff0c;就再开个篇写一写。C# 9&#xff0c;对应的是 Dotnet 5.0。这个出来也有些日子了&#xff0c;不过好像群里很多人还是没往这个版本走。我这边现在是全线已经转向了 5.0&#xff0c;还是我经常说的那个原因&#xff1…

《C语言及程序设计》实践参考——当年第几天(数组方案)

返回&#xff1a;贺老师课程教学链接 项目要求 【项目3-当年第几天(数组方案)】 当年第几天中定义一个函数&#xff0c;其参数为年、月、日的值&#xff0c;返回这一天为该年的第几天。要求在main函数中输入年月日&#xff0c;然后调用这个函数求值&#xff0c;并在main函数中…

开发与研发(转)

按&#xff1a;这几天我一直在写这篇东西&#xff0c;本来是胸有成竹&#xff0c;没想到后来越写越发现自己在这个题目下有太多话想说&#xff0c;而以我现在的能力又不能很好地概括总结&#xff0c;以至于越写越长&#xff0c;文章结构也变得混乱&#xff0c;到后来修改的时候…

java和python哪个学习编程_初学编程,选Java还是Python?

从岗位需求量的角度目前Java仍然是最火的编程语言&#xff0c;在编程语言排行榜中Java常年稳居第一&#xff0c;和他不相上下的C语言&#xff0c;是面向过程的编程语言&#xff0c;简言之面向过程的语言适合于那些有强大数学基础、逻辑学基础的人。如果你学编程的目的是打算上班…

sql 百分数_SQL经典50题笔记

SQL语句执行顺序(8) SELECT (9)DISTINCT<Select_list> (1) FROM <left_table> (3) <join_type>JOIN<right_table> (2) ON<join_condition> (4) WHERE<where_condition> (5) GROUP BY<group_by_list> (6) WITH {CUBE|ROLLUP} (7) HAV…

Android 横竖屏切换的处理 (转载)

Android 中&#xff0c;缺省情况下屏幕的切换动会销毁当前的Activity&#xff0c;并且重启Activity。当然这种缺省的处理方式可能不符合我们的要求。 可以有多种选择改变这种处理方式。 一种方式是在销毁Activity前保存数据&#xff0c;在Activity再次Create的时候载入配置。on…

这种秀恩爱你见过吗?

1 棒棒哒&#xff0c;做的好2 程序员的日常3 一群单身鱼都看呆了4 最佳COS5 自拍达喵6 为什么你们能长这么大&#xff1f;懵逼了7 请用一个词形容这张图你点的每个赞&#xff0c;我都认真当成了喜欢

Layui宣布下线,不自禁的感叹一下,回忆啊

简单唠唠 其实对于前端的信息好久没关注了&#xff0c;一堆后端的Bug要撸&#xff0c;实在没有时间&#xff1b;由于浏览器收藏的东西比较多&#xff0c;于是就想抽点时间归归类&#xff0c;方便查询信息&#xff1b;趁这个机会就挨个点进去瞅一遍&#xff08;随便摸摸鱼&#…

《C语言及程序设计》程序填空——字符数组与字符串处理

返回&#xff1a;贺老师课程教学链接 1、编写一函数&#xff0c;由实参传来一个字符串&#xff0c;统计此字符串中字母、数字、空格和其它字符的个数&#xff0c;在主函数中输入字符串以及输出上述的结果。请将下面的程序补充完整。#include<stdio.h> #include<string…

csv文件设置每个cell大小_Python对文本文件和Excel的处理机制

有头发且有趣的码农万里挑一~ 96有料叔 | 一位有故事的程序猿读取文件内容的方式直接一次性读取文件内容按行读取文件内容将读取的文件内容形成一个列表直接一次性读取文件内容open()需要手动释放资源&#xff0c;最后使用close()with open() as…使用with … as…&#xff0c;…

给图片添加水印

许久没写代码了&#xff0c;许久没上博客园了&#xff0c;许久没有写博文了。using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Drawing.Drawing2D;using System.Drawing.Imaging;using Syste…

idea2020.2.2怎么创建web项目_创建Vue3.0的项目

1. 查看Vue的环境版本Vue -V如果版本低于4.0&#xff0c;则需要升级Vue的版本npm install -g vue/cli2. 创建Vue 3.0的项目3. VS Code 的环境配置安装Extension&#xff1a;ESLint&#xff0c; Vetur。VS Code基于ESLint的Auto Save功能&#xff0c;可以很好的格式化代码&#…

揭秘奢侈品代工厂内幕:千元以上的大牌墨镜,成本甚至不过百!

▲ 点击查看纵观全球没有哪个国家像中国这样几乎所有领域都在发力世界能研发高铁的国家&#xff0c;不超过十个&#xff0c;中国在列&#xff1b;世界能建造军舰的国家&#xff0c;不超过十个&#xff0c;中国在列&#xff1b;世界能研发第五代隐身战机的国家&#xff0c;不超过…