一、準備
- 使用vs2019建立ASP.NET Core Web應用程式,選用api模闆:
ASP.NET Core 3.1 WebApi+JWT+Swagger+EntityFrameworkCore建構REST API - 安裝相關的NuGet包:
ASP.NET Core 3.1 WebApi+JWT+Swagger+EntityFrameworkCore建構REST API
二、編碼
- 首先編寫資料庫模型: 使用者表 User.cs:
ASP.NET Core 3.1 WebApi+JWT+Swagger+EntityFrameworkCore建構REST API
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接口,這裡簡單定義幾個添加查詢的方法:
ASP.NET Core 3.1 WebApi+JWT+Swagger+EntityFrameworkCore建構REST API
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配置對象:
ASP.NET Core 3.1 WebApi+JWT+Swagger+EntityFrameworkCore建構REST API
/// <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
然後執行ASP.NET Core 3.1 WebApi+JWT+Swagger+EntityFrameworkCore建構REST API Update-Database
此時資料庫已經成功生成:ASP.NET Core 3.1 WebApi+JWT+Swagger+EntityFrameworkCore建構REST API ASP.NET Core 3.1 WebApi+JWT+Swagger+EntityFrameworkCore建構REST API - 下面是controller: 先建一個資料傳輸實體,友善統一controller的傳回值:
ASP.NET Core 3.1 WebApi+JWT+Swagger+EntityFrameworkCore建構REST API
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
——本文使用【Typora】+【EasyBlogImageForTypora】編輯
歡迎關注我的公衆号,一起學習。
如果本文對您有所幫助,您可以點選右下方的【推薦】按鈕支援一下;文中如有不妥之處,還望指正,非常感謝!!!
作者:xhznl
出處:http://www.cnblogs.com/xhznl/
文章可以轉載,但請注明出處