一、准备

  • 使用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. 「雕爷学编程」Arduino动手做(27)——BMP280气压传感器

    37款传感器与模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的.鉴于本人手头积累了一些传感器和模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的,这里 ...

  2. Django启动

    Django启动 (一)CMD中创建启动: 1.配置好django-admin.exe环境变量,切换到项目文件夹路径 切换磁盘:>>>E: 显示文件列表:>>>di ...

  3. 解决删除~/Library/Caches/CocoaPods/search_index.json重新pod search还是不起作用

    今天新苹果机安装cocoapods,安装完以后发现怎么pod search 都没有用 命令行提示: swhcxp@iosdevmac ~ % pod search Almofire Setup com ...

  4. tableView reloadData页面跳动问题

    参考:https://www.jianshu.com/p/5f033fdd4ddb 一般情况下 if (@available(iOS 11.0, *)) { self.estimatedRowHeig ...

  5. AVL树的创建--C语言实现

    AVL树是一种自平衡(Self-balancing)二叉查找树(Binary Search Tree),要求任何一个节点的左子树和右子树的高度之差不能超过1. AVL树的插入操作首先会按照普通二叉查找 ...

  6. 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 ...

  7. java第十二周课后作业0523

    1.编写一个程序,实现字符串大小写的转换并倒序输出.要求如下(1)使用for循环将字符串“ Hello world”从最后一个字符开始遍历(2)遍历的当前字符如果是大写字符,就使用 toLower C ...

  8. 【Java_SSM】(三)maven中的配置文件setting的配置

    这篇博文我们介绍两方面:如何修改setting.xml文件及相应配置(本文maven版本为3.5.0) (1)首先打开maven文件目录--conf,会看见如下目录 (2)复制setting.xml文 ...

  9. queue.Queue()

    一.构造方法 Queue是构造方法,函数签名是Queue(maxsize=0) ,其中maxsize设置队列的大小. 二.实例方法 Queue.qsize(): 返回queue的近似值.注意:qsiz ...

  10. iOS 的尾调用优化原理

    背景: 今天聊代码规范的问题的时候说了一下尾调用的问题. 一:概念: 什么是尾调用? 尾调用(Tail Call):某个函数的最后一步仅仅只是调用了一个函数(可以是自身,可以是另一个函数). 注意 “ ...