ASP.NET Core 3.1 WebApi+JWT+Swagger+EntityFrameworkCore构建REST API
一、准备
- 使用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的更多相关文章
- ASP.NET Core 1.0 中使用 Swagger 生成文档
github:https://github.com/domaindrivendev/Ahoy 之前文章有介绍在ASP.NET WebAPI 中使用Swagger生成文档,ASP.NET Core 1. ...
- asp.net core系列 38 WebAPI 返回类型与响应格式--必备
一.返回类型 ASP.NET Core 提供以下 Web API Action方法返回类型选项,以及说明每种返回类型的最佳适用情况: (1) 固定类型 (2) IActionResult (3) Ac ...
- asp.net core 3.0 中使用 swagger
asp.net core 3.0 中使用 swagger Intro 上次更新了 asp.net core 3.0 简单的记录了一下 swagger 的使用,那个项目的 api 比较简单,都是匿名接口 ...
- 用Swashbuckle给ASP.NET Core的项目自动生成Swagger的API帮助文档
博客搬到了fresky.github.io - Dawei XU,请各位看官挪步.最新的一篇是:用Swashbuckle给ASP.NET Core的项目自动生成Swagger的API帮助文档.
- asp.net core 2.0 webapi集成signalr
asp.net core 2.0 webapi集成signalr 在博客园也很多年了,一直未曾分享过什么东西,也没有写过博客,但自己也是汲取着博客园的知识成长的: 这两天想着不能这么无私,最近.N ...
- ASP.NET Core 3.0 一个 jwt 的轻量角色/用户、单个API控制的授权认证库
目录 说明 一.定义角色.API.用户 二.添加自定义事件 三.注入授权服务和中间件 三.如何设置API的授权 四.添加登录颁发 Token 五.部分说明 六.验证 说明 ASP.NET Core 3 ...
- ASP.NET Core 2.2 WebApi 系列【九】使用SignalR (作者:tenghao510 ) 学习及内容补充
原文地址: ASP.NET Core 2.2 WebApi 系列[九]使用SignalR 今天,看到了大牛的这篇博文, 发了一下评论, 我很惊喜, 没想到他很快就回复了我, 而且通过QQ帮助了S ...
- ASP.NET Core on K8S学习初探(3)部署API到K8S
在上一篇<基本概念快速一览>中,我们把基本的一些概念快速地简单地不求甚解地过了一下,本篇开始我们会将ASP.NET Core WebAPI部署到K8S,从而结束初探的旅程. Section ...
- 《ASP.NET Core跨平台开发从入门到实战》Web API自定义格式化protobuf
<ASP.NET Core跨平台开发从入门到实战>样章节 Web API自定义格式化protobuf. 样章 Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于 ...
随机推荐
- 「雕爷学编程」Arduino动手做(27)——BMP280气压传感器
37款传感器与模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的.鉴于本人手头积累了一些传感器和模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的,这里 ...
- Django启动
Django启动 (一)CMD中创建启动: 1.配置好django-admin.exe环境变量,切换到项目文件夹路径 切换磁盘:>>>E: 显示文件列表:>>>di ...
- 解决删除~/Library/Caches/CocoaPods/search_index.json重新pod search还是不起作用
今天新苹果机安装cocoapods,安装完以后发现怎么pod search 都没有用 命令行提示: swhcxp@iosdevmac ~ % pod search Almofire Setup com ...
- tableView reloadData页面跳动问题
参考:https://www.jianshu.com/p/5f033fdd4ddb 一般情况下 if (@available(iOS 11.0, *)) { self.estimatedRowHeig ...
- AVL树的创建--C语言实现
AVL树是一种自平衡(Self-balancing)二叉查找树(Binary Search Tree),要求任何一个节点的左子树和右子树的高度之差不能超过1. AVL树的插入操作首先会按照普通二叉查找 ...
- DFS序--一般都要转化为顶点到每个点
There is a rooted tree with n nodes, number from 1-n. Root’s number is 1.Each node has a value ai. I ...
- java第十二周课后作业0523
1.编写一个程序,实现字符串大小写的转换并倒序输出.要求如下(1)使用for循环将字符串“ Hello world”从最后一个字符开始遍历(2)遍历的当前字符如果是大写字符,就使用 toLower C ...
- 【Java_SSM】(三)maven中的配置文件setting的配置
这篇博文我们介绍两方面:如何修改setting.xml文件及相应配置(本文maven版本为3.5.0) (1)首先打开maven文件目录--conf,会看见如下目录 (2)复制setting.xml文 ...
- queue.Queue()
一.构造方法 Queue是构造方法,函数签名是Queue(maxsize=0) ,其中maxsize设置队列的大小. 二.实例方法 Queue.qsize(): 返回queue的近似值.注意:qsiz ...
- iOS 的尾调用优化原理
背景: 今天聊代码规范的问题的时候说了一下尾调用的问题. 一:概念: 什么是尾调用? 尾调用(Tail Call):某个函数的最后一步仅仅只是调用了一个函数(可以是自身,可以是另一个函数). 注意 “ ...