一、准备

  • 使用vs2019新建ASP.NET Core Web应用程序,选用api模板:

  • 安装相关的NuGet包:

二、编码

  • 首先编写数据库模型:



    用户表 User.cs:
public class User
{
[Key]
public Guid ID { get; set; } [Required]
[Column(TypeName = "VARCHAR(16)")]
public string UserName { get; set; } [Required]
[Column(TypeName = "VARCHAR(16)")]
public string Password { get; set; }
}

数据库上下文 DemoContext.cs,在数据库创建时增加一条种子数据admin:

public class DemoContext : DbContext
{
public DemoContext(DbContextOptions<DemoContext> options)
: base(options)
{ } public DbSet<User> Users { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<User>().HasData(new User
{
ID = Guid.Parse("94430DDF-E6E1-4836-A7D2-49A9FCEF722E"),
UserName = "admin",
Password = "123456"
});
}
}
  • 编写数据访问服务:



    IUserService接口,这里简单定义几个添加查询的方法:
public interface IUserService
{
Task<IEnumerable<User>> GetUserAsync(); Task<User> GetUserAsync(Guid id); Task<User> GetUserAsync(string username, string password); Task<User> AddUserAsync(string username, string password);
}

UserService实现类:

public class UserService : IUserService
{
private readonly DemoContext context; public UserService(DemoContext context)
{
this.context = context ?? throw new ArgumentNullException(nameof(context));
} public async Task<User> AddUserAsync(string username, string password)
{
User user = new User();
user.ID = Guid.NewGuid();
user.UserName = username;
user.Password = password;
await context.Users.AddAsync(user);
context.SaveChanges();
return user;
} public async Task<User> GetUserAsync(string username, string password)
{
return await context.Users.FirstOrDefaultAsync(p => p.UserName == username && p.Password == password);
} public async Task<IEnumerable<User>> GetUserAsync()
{
return await context.Users.ToListAsync();
} public async Task<User> GetUserAsync(Guid id)
{
return await context.Users.FirstOrDefaultAsync(p => p.ID == id);
} }
  • appsettings.json中增加jwt,efcore相关的配置 JwtSetting、ConnectionStrings:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"JwtSetting": {
"SecurityKey": "88d082e6-5672-4c6c-bc42-6fcce20fbf51", // 密钥
"Issuer": "jwtIssuertest", // 颁发者
"Audience": "jwtAudiencetest", // 接收者
"ExpireSeconds": 3600 // 过期时间(3600)
},
"ConnectionStrings": {
"DemoContext": "data source=.;Initial Catalog=WebApiDemoDB;User ID=sa;Password=123456;MultipleActiveResultSets=True;App=EntityFramework"
}
}
  • 增加jwt配置对象:

    /// <summary>
/// jwt配置对象
/// </summary>
public class JwtSetting
{
public string SecurityKey { get; set; }
public string Issuer { get; set; }
public string Audience { get; set; }
public int ExpireSeconds { get; set; }
}
public static class AppSettings
{
public static JwtSetting JwtSetting { get; set; } /// <summary>
/// 初始化jwt配置
/// </summary>
/// <param name="configuration"></param>
public static void Init(IConfiguration configuration)
{
JwtSetting = new JwtSetting();
configuration.Bind("JwtSetting", JwtSetting);
}
}
  • 在Startup.cs中配置相关服务和中间件:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
} public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
AppSettings.Init(Configuration); services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" });
// Set the comments path for the Swagger JSON and UI.
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
c.IncludeXmlComments(xmlPath);
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
{
Description = "在下框中输入请求头中需要添加Jwt授权Token:Bearer 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"}
},new string[] { }
}
});
}); services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = AppSettings.JwtSetting.Issuer,
ValidAudience = AppSettings.JwtSetting.Audience,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(AppSettings.JwtSetting.SecurityKey)),
// 默认允许 300s 的时间偏移量,设置为0
ClockSkew = TimeSpan.Zero,
};
}); services.AddCors(options =>
{
options.AddPolicy("any",
builder =>
{
builder.AllowAnyMethod()
.AllowAnyOrigin()
.AllowAnyHeader();
});
}); services.AddControllers();
services.AddScoped<IUserService, UserService>();
services.AddDbContext<DemoContext>(opt => opt.UseSqlServer(Configuration.GetConnectionString("DemoContext")));
} // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseAuthentication(); if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
} app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
}); app.UseRouting(); app.UseAuthorization(); //CORS 中间件必须配置为在对 UseRouting 和 UseEndpoints的调用之间执行。 配置不正确将导致中间件停止正常运行。
app.UseCors("any"); app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
  • 打开项目文件,增加项目xml文档生成配置,swagger需要用到:
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>$(NoWarn);1591</NoWarn>

  • 数据库迁移:

    打开程序包管理控制台:执行命令Add-Migration Initial



    然后执行Update-Database



    此时数据库已经成功生成:

  • 下面是controller:



    先建一个数据传输实体,方便统一controller的返回值:
public class BaseDto<T>
{
public BaseDto(StatusCode code, string message)
{
Code = code;
Message = message;
} public BaseDto(StatusCode code, string message, T data)
{
Code = code;
Message = message;
Data = data;
} public StatusCode Code { get; set; } public string Message { get; set; } public T Data { get; set; }
} public enum StatusCode
{
Success = 0,
Error = 1,
}

UserController:

/// <summary>
/// 用户
/// </summary>
[Authorize]
[Route("api/[controller]")]
[ApiController]
public class UserController : ControllerBase
{
private readonly IUserService userService; public UserController(IUserService userService)
{
this.userService = userService;
} /// <summary>
/// 所有用户
/// </summary>
/// <returns></returns>
[Route("")]
[HttpGet]
public async Task<ActionResult<BaseDto<IEnumerable<User>>>> Get()
{
var users = await userService.GetUserAsync();
BaseDto<IEnumerable<User>> dto = new BaseDto<IEnumerable<User>>(Dto.StatusCode.Success, "", users);
return Ok(dto);
} /// <summary>
/// 当前用户
/// </summary>
/// <returns></returns>
[Route("me")]
[HttpGet]
public async Task<ActionResult<BaseDto<User>>> UserInfo()
{
string id = User.FindFirst("id")?.Value;
var user = await userService.GetUserAsync(Guid.Parse(id));
BaseDto<User> dto = new BaseDto<User>(Dto.StatusCode.Success, "", user);
return Ok(dto);
} /// <summary>
/// 根据ID获取用户
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[Route("{id}")]
[HttpGet]
public async Task<ActionResult<BaseDto<User>>> Get(Guid id)
{
var user = await userService.GetUserAsync(id);
BaseDto<User> dto = new BaseDto<User>(Dto.StatusCode.Success, "", user);
return Ok(dto);
} /// <summary>
/// 添加用户
/// </summary>
/// <param name="loginParameter"></param>
/// <returns></returns>
[HttpPost]
public async Task<ActionResult<BaseDto<User>>> Add(LoginParameter loginParameter)
{
var user = await userService.AddUserAsync(loginParameter.UserName, loginParameter.Password);
BaseDto<User> dto = new BaseDto<User>(Dto.StatusCode.Success, "", user);
return Ok(dto);
}
} public class LoginParameter
{
public string UserName { get; set; } public string Password { get; set; }
}

TokenController:

/// <summary>
/// 鉴权
/// </summary>
[Route("api/[controller]")]
[ApiController]
public class TokenController : ControllerBase
{
private readonly IUserService userService; public TokenController(IUserService userService)
{
this.userService = userService;
} /// <summary>
/// 获取token
/// </summary>
/// <param name="loginParameter"></param>
/// <returns></returns>
[AllowAnonymous]
[HttpPost(Name = nameof(Login))]
public async Task<ActionResult<BaseDto<object>>> Login([FromBody]LoginParameter loginParameter)
{
var user = await userService.GetUserAsync(loginParameter.UserName, loginParameter.Password);
if (user != null)
{
var token = AppHelper.Instance.GetToken(user);
BaseDto<object> dto = new BaseDto<object>(Dto.StatusCode.Success, "", new { token });
return Ok(dto);
}
return Ok(new BaseDto<object>(Dto.StatusCode.Error, "", null));
}
}

AppHelper中生成token的方法:

public class AppHelper
{
public readonly static AppHelper Instance = new AppHelper(); private AppHelper() { } /// <summary>
/// 生成token
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
public string GetToken(User user)
{
//创建用户身份标识,可按需要添加更多信息
var claims = new Claim[]
{
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim("id", user.ID.ToString(), ClaimValueTypes.Integer32), // 用户id
new Claim("name", user.UserName), // 用户名
}; var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(AppSettings.JwtSetting.SecurityKey));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); //创建令牌
var token = new JwtSecurityToken(
issuer: AppSettings.JwtSetting.Issuer,
audience: AppSettings.JwtSetting.Audience,
signingCredentials: creds,
claims: claims,
notBefore: DateTime.Now,
expires: DateTime.Now.AddSeconds(AppSettings.JwtSetting.ExpireSeconds)
); string jwtToken = new JwtSecurityTokenHandler().WriteToken(token); return jwtToken;
} }

三、效果

运行项目,浏览器访问:



测试一下用户接口:



这时返回401错误,因为我们还没有鉴权

使用admin/123456获取token:



拿到token 点击authorize:



然后再测试用户接口:



此时已经可以正常请求。

代码:https://github.com/xiajingren/NetCore3.1-WebApi-Demo

ASP.NET Core 3.1 WebApi+JWT+Swagger+EntityFrameworkCore构建REST API的更多相关文章

  1. ASP.NET Core 1.0 中使用 Swagger 生成文档

    github:https://github.com/domaindrivendev/Ahoy 之前文章有介绍在ASP.NET WebAPI 中使用Swagger生成文档,ASP.NET Core 1. ...

  2. asp.net core系列 38 WebAPI 返回类型与响应格式--必备

    一.返回类型 ASP.NET Core 提供以下 Web API Action方法返回类型选项,以及说明每种返回类型的最佳适用情况: (1) 固定类型 (2) IActionResult (3) Ac ...

  3. asp.net core 3.0 中使用 swagger

    asp.net core 3.0 中使用 swagger Intro 上次更新了 asp.net core 3.0 简单的记录了一下 swagger 的使用,那个项目的 api 比较简单,都是匿名接口 ...

  4. 用Swashbuckle给ASP.NET Core的项目自动生成Swagger的API帮助文档

    博客搬到了fresky.github.io - Dawei XU,请各位看官挪步.最新的一篇是:用Swashbuckle给ASP.NET Core的项目自动生成Swagger的API帮助文档.

  5. asp.net core 2.0 webapi集成signalr

    asp.net core 2.0 webapi集成signalr   在博客园也很多年了,一直未曾分享过什么东西,也没有写过博客,但自己也是汲取着博客园的知识成长的: 这两天想着不能这么无私,最近.N ...

  6. ASP.NET Core 3.0 一个 jwt 的轻量角色/用户、单个API控制的授权认证库

    目录 说明 一.定义角色.API.用户 二.添加自定义事件 三.注入授权服务和中间件 三.如何设置API的授权 四.添加登录颁发 Token 五.部分说明 六.验证 说明 ASP.NET Core 3 ...

  7. ASP.NET Core 2.2 WebApi 系列【九】使用SignalR (作者:tenghao510 ) 学习及内容补充

    原文地址:  ASP.NET Core 2.2 WebApi 系列[九]使用SignalR 今天,看到了大牛的这篇博文,  发了一下评论, 我很惊喜, 没想到他很快就回复了我,  而且通过QQ帮助了S ...

  8. ASP.NET Core on K8S学习初探(3)部署API到K8S

    在上一篇<基本概念快速一览>中,我们把基本的一些概念快速地简单地不求甚解地过了一下,本篇开始我们会将ASP.NET Core WebAPI部署到K8S,从而结束初探的旅程. Section ...

  9. 《ASP.NET Core跨平台开发从入门到实战》Web API自定义格式化protobuf

    <ASP.NET Core跨平台开发从入门到实战>样章节 Web API自定义格式化protobuf. 样章 Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于 ...

随机推荐

  1. maven and dubbo

    maven是什么 maven是一个项目管理和构建自动化工具. 核心概念 pom (project object model) mvn compile 编译 mvn package 编译成一个jar的包 ...

  2. 3.3 Go浮点型

    1.Go浮点型 Go 语言提供了两种精度的浮点数,float32 和 float64,编译器默认声明为float64 小数类型就是存放小数的,如1.2 0.005 -2.32 package main ...

  3. java 字符串转为list

     List<String> idList = Arrays.asList(irIds.split(",")); 

  4. Excel导出到DataSet

    #region 导入excel 返回Dataset public DataSet ExecleDataSet(string filename, string file, string Type) { ...

  5. POJ1733

    题目链接:https://vjudge.net/problem/POJ-1733 解题思路:并查集+离散化 AC代码: #include <iostream> #include <c ...

  6. 【MySQL】大白话讲讲主从架构的几种搭配方式详解

    话不多,直接上图: 主要来详细讲讲各个搭配 1>一主一从(成本最低): 并不是用来提高程序性能的,主要是用来做数据的热备(即如果master节点挂掉的话,slave节点能充当master节点), ...

  7. Angular SPA基于Ocelot API网关与IdentityServer4的身份认证与授权(二)

    上文已经介绍了Identity Service的实现过程.今天我们继续,实现一个简单的Weather API和一个基于Ocelot的API网关. 回顾 <Angular SPA基于Ocelot ...

  8. windows 10 2016 企业版 长期服务 激活方式

    试了很多,失败. 使用这个ok———————————————————————————————— 使用方式: 2.1.下载AAct.exe  https://www.baidu.com/link?url ...

  9. 漫谈碎片化学习(Fragmentation learning)

    碎片化学习(Fragmentation Learning) 从一个互联网小段子讲起: 某天,美国情报部门FBI应奥巴马的要求,做相关汇报:“报告总统,经FBI分析,中国‘短信’中35%是节日祝福语,2 ...

  10. java第十三周课后作业 0529

    1.把多个企鹅的信息添加到集合中查看企鹅的数量及所有企鹅的信息删除集合中部分企鹅的元素判断集合中是否包含指定企鹅 package homework; import java.util.ArrayLis ...