一、准备

  • 使用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. spark机器学习从0到1主成分分析-PCA (八)

      PCA 一.概念 主成分分析(Principal Component Analysis)是指将多个变量通过线性变换以选出较少数重要变量的一种多元统计分析方法,又称为主成分分析.在实际应用场合中,为 ...

  2. npm加载包报错 :syscall access

    $ npm install --save-dev babel-plugin-syntax-dynamic-import npm WARN checkPermissions Missing write ...

  3. HttpServletResponse和HttpServletRequest的简单实用

    1.HttpServletResponse web服务器接收到客户端的http请求,针对这个请求,分别创建一一个代表请求的HttpServletRequest 对象,代表响应的- -个HttpServ ...

  4. WXML属性一览表

    id属性 <view id="xxx"></view> class属性 <view class="xxx"></vie ...

  5. 【java】关键字volatile

    volatile 1. 含义: volatile是JVM提供的轻量级的同步机制,具有三个特点:保证可见性.不保证原子性.禁止指令重排. 1.1 保证可见性 一个线程修改了共享变量并写回主内存,其他线程 ...

  6. [PHP学习教程 - 类库]002.FTP操作(FTP)

    引言:FTP是大家上传至站点服务器必须要使用的协议.现在常用的FTP客户端工具也很多,如:8uftp,FlashFXP,....但是使用客户端工具就无法真正与自动化联系起来.所以今天,我们为大家讲一下 ...

  7. [安卓基础] 004.运行app

    运行你的app 这篇课程会教你: 1.如何在设备上运行你的app. 2.如何在模拟器上运行你的app. 当然,在学习之前,你还需要知道: 1.如何使用设备. 2.如何使用模拟器. 3.管理你的项目. ...

  8. python2.7入门 01

    进入python官网  http://www.python.org/download/ 下载python2.7.x  版 下载安装后配置环境变量    在path中——>>>把安装路 ...

  9. Excel常用小方法

    Excel快捷键 Excel中处理工作表的快捷键 插入新工作表 Shift+F11或Alt+Shift+F1 移动到工作簿中的下一张工作表 Ctrl+PageDown 移动到工作簿中的上一张工作表 C ...

  10. Vue 全选/取消全选,反选/取消反选

    这是一个组件: <template> <div> <div> <input type="checkbox" v-model="i ...