前言

上一篇已经介绍了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();

结构搭建

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

以下是各个类的定义:

// 用户注册请求参数
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中的UserManagerUserManager封装了很多用户操作的现成方法。

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"));

测试一下

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

这个规则在注册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:

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

最后

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

参考:

ASP.NET Core 简介 Identity | Microsoft Docs

Mohamad Lawand - DEV Community

asp.net core使用identity+jwt保护你的webapi(二)——获取jwt token的更多相关文章

  1. ASP.NET Core 之 Identity 入门(三)

    前言 在上一篇文章中,我们学习了 CookieAuthentication 中间件,本篇的话主要看一下 Identity 本身. 最早2005年 ASP.NET 2.0 的时候开始, Web 应用程序 ...

  2. [转]ASP.NET Core 之 Identity 入门(三)

    本文转自:http://www.cnblogs.com/savorboard/p/aspnetcore-identity3.html 前言 在上一篇文章中,我们学习了 CookieAuthentica ...

  3. 【分分钟内搭建一个带用户系统的博客程序(一)用户系统】asp.net core的Identity真香,EF真香!

    不用不知道,一用香到爆. 老哥是个屌丝前端,但也想写点web应用耍一耍.之前弄过了NodeJs,也弄过JAVA,最近由于写游戏的原因用C#,索性上手一波asp.net core. 这篇博客记录的是,如 ...

  4. ASP.NET Core 之 Identity 入门(一)

    前言 在 ASP.NET Core 中,仍然沿用了 ASP.NET里面的 Identity 组件库,负责对用户的身份进行认证,总体来说的话,没有MVC 5 里面那么复杂,因为在MVC 5里面引入了OW ...

  5. ASP.NET Core 之 Identity 入门(二)

    前言 在 上篇文章 中讲了关于 Identity 需要了解的单词以及相对应的几个知识点,并且知道了Identity处在整个登入流程中的位置,本篇主要是在 .NET 整个认证系统中比较重要的一个环节,就 ...

  6. [转]ASP.NET Core 之 Identity 入门(二)

    本文转自:http://www.cnblogs.com/savorboard/p/aspnetcore-identity2.html 前言 在 上篇文章 中讲了关于 Identity 需要了解的单词以 ...

  7. [转]ASP.NET Core 之 Identity 入门(一)

    本文转自:http://www.cnblogs.com/savorboard/p/aspnetcore-identity.html 前言 在 ASP.NET Core 中,仍然沿用了 ASP.NET里 ...

  8. 如何基于asp.net core的Identity框架在mysql上作身份验证处理

    首先了解这个概念,我一开始也是理解和掌握基本的概念,再去做程序的开发.Identity框架是微软自己提供,基于.net core平台,可拓展.轻量 级.面向多个数据库的身份验证框架.IdentityS ...

  9. 在Asp.Net Core中使用中间件保护非公开文件

    在企业开发中,我们经常会遇到由用户上传文件的场景,比如某OA系统中,由用户填写某表单并上传身份证,由身份管理员审查,超级管理员可以查看. 就这样一个场景,用户上传的文件只能有三种人看得见(能够访问) ...

  10. ASP.NET Core 之 Identity 入门(转载)

    原文地址:https://www.cnblogs.com/gongap/p/9504562.html 前言 在 ASP.NET Core 中,仍然沿用了 ASP.NET里面的 Identity 组件库 ...

随机推荐

  1. C#进阶系列——WebApi 接口返回值不困惑:返回值类型详解

    前言:已经有一个月没写点什么了,感觉心里空落落的.今天再来篇干货,想要学习Webapi的园友们速速动起来,跟着博主一起来学习吧.之前分享过一篇 C#进阶系列——WebApi接口传参不再困惑:传参详解  ...

  2. 配置Report Server超时

    http://blogs.msdn.com/b/mariae/archive/2009/09/24/troubleshooting-timeout-errors-in-reporting-servic ...

  3. linux信号机制与python信号量

    1.信号本质 软中断信号(signal,又简称为信号)用来通知进程发生了异步事件.在软件层次上是对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的.信号是进程间 ...

  4. docker nodejs 基本应用

    1. 安装docker 环境 2. nodejs  应用布局 package.json { "name": "docker-centos-hello", &qu ...

  5. 怎么样调试正在运行的exe?

    最近在调虚幻的编辑器的时候遇到了一个问题. 调试模式运行UE4Editor.exe 实际上只是一个带参的命令行. 打开后,它又通过这个参数生成了一份详细配置,重新调用了自己.如图 这就悲剧了,断点都没 ...

  6. UVA 10603 Fill

    题意: 题目的意思是倒水,给出的四个数据是第一个水杯,第二个水杯,第三个水杯,和目标水量.一开始只有第三个水杯是满的,剩下的水杯是空的.倒水的时候只能把倒水出来的这个杯子倒空,或是倒水进去的杯子倒满. ...

  7. app调用支付宝支付 笔记

    1.提交各种申请 2.通过后进入支付宝开放平台  --> 管理中心 -->创建应用  --> 填写相关信息 提交等待审核通过(1,2天)   3.下载集成包(https://doc. ...

  8. 解决ionic在Android和iOS的一些样式上的冲突

    //设置默认返回按钮的文字 $ionicConfigProvider.backButton.previousTitleText(false).text('返回'); // 设置全局 $http 超时 ...

  9. jQuery学习笔记之Ajax用法详解

    这篇文章主要介绍了jQuery学习笔记之Ajax用法,结合实例形式较为详细的分析总结了jQuery中ajax的相关使用技巧,包括ajax请求.载入.处理.传递等,需要的朋友可以参考下 本文实例讲述了j ...

  10. 路由交换01-----ICMP协议

    路由交换协议------ICMP ICMP协议 ICMP (InternetControl Message Protocol)协议是TCP/IP协议簇的核心协议之一,用来在网络设备之间传递各种差错和控 ...