StarBlog博客开发笔记:身份认证功能
身份认证使用JWT,关于AspNetCore的身份认证和JWT可以看看我之前这篇博客 先安装nuget包 dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer 在Services目录下新建一个AuthService类,先留着不写代码,等把准备工作完成了再来。 用户模型 在 StarBlog.Data 项目的 Models
目录12 个章节
身份认证使用JWT,关于AspNetCore的身份认证和JWT可以看看我之前这篇博客
先安装nuget包
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
在Services目录下新建一个AuthService类,先留着不写代码,等把准备工作完成了再来。
用户模型
在 StarBlog.Data 项目的 Models 目录下新建 User 类
代码如下
namespace StarBlog.Data.Models;
public class User {
public string Id { get; set; }
public string Name { get; set; }
public string Password { get; set; }
}
配置
编辑appsettings.json
添加配置
Issuer是token的发行者,我写了这个项目的名称Audience是token的接受者(使用者),我写了管理后台的项目名称Key是用来加密token的密码,找一个随机密码生成器生成一个就好了,注意位数要8的位数
"SecuritySettings": {
"Token": {
"Issuer": "starblog",
"Audience": "starblog-admin-ui",
"Key": "Pox40XC.D5>v^2B7+KAt%WfXaz0B6zC5"
}
}
PS:本文里这种把Key放在配置文件的做法并不安全,特别是在开源项目中,这种机密数据用环境变量来存更好,MSDN上有关于安全这方面的更详细的资料,如果上生产项目的话可以关注一下。这里为了不增加复杂度我就直接偷懒把Key放在appsettings.json里了,见谅哈~
配置模型
写一个实体类,方便和配置绑定起来使用
在Models/Config目录下新建SecuritySettings.cs,代码如下
namespace StarBlog.Web.Models.Config;
public class SecuritySettings {
public Token Token { get; set; }
}
public class Token {
public string Issuer { get; set; }
public string Audience { get; set; }
public string Key { get; set; }
}
注册服务
为了Program.cs文件内的代码整洁,我们用扩展方法的方式来注册服务
在Extensions目录下新建ConfigureAppSettings.cs,用来绑定配置,代码如下
using StarBlog.Web.Models.Config;
namespace StarBlog.Web.Extensions;
public static class ConfigureAppSettings {
public static void AddSettings(this IServiceCollection services, IConfiguration configuration) {
// 安全配置
services.Configure<SecuritySettings>(configuration.GetSection(nameof(SecuritySettings)));
}
}
继续新建ConfigureAuth.cs文件,用来注册认证需要的一些服务,代码如下
using System.Text;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using StarBlog.Web.Models.Config;
using StarBlog.Web.Services;
namespace StarBlog.Web.Extensions;
public static class ConfigureAuth {
public static void AddAuth(this IServiceCollection services, IConfiguration configuration) {
services.AddScoped<AuthService>();
services.AddAuthentication(options => {
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options => {
var secSettings = configuration.GetSection(nameof(SecuritySettings)).Get<SecuritySettings>();
options.TokenValidationParameters = new TokenValidationParameters {
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuer = true,
ValidateIssuerSigningKey = true,
ValidIssuer = secSettings.Token.Issuer,
ValidAudience = secSettings.Token.Audience,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secSettings.Token.Key)),
ClockSkew = TimeSpan.Zero
};
});
}
}
这里面的AuthService还没写,但不急,先来注册服务
编辑Program.cs文件,添加这两行代码
builder.Services.AddSettings(builder.Configuration);
builder.Services.AddAuth(builder.Configuration);
身份认证关键代码
AspNetCore框架已经把身份认证的功能内置了,所以我们要做的事情很少,只需要生成一个JWT token给客户端就行了。
那就开始吧
模型
先在 ViewModels 目录下新建两个类,分别是 LoginToken 和 LoginUser。
代码如下
namespace StarBlog.Web.ViewModels;
public class LoginToken {
public string Token { get; set; }
public DateTime Expiration { get; set; }
}
namespace StarBlog.Web.ViewModels;
public class LoginUser {
public string Username { get; set; }
public string Password { get; set; }
}
AuthService
先写上依赖注入
public class AuthService {
private readonly SecuritySettings _securitySettings;
private readonly IBaseRepository<User> _userRepo;
public AuthService(IOptions<SecuritySettings> options, IBaseRepository<User> userRepo) {
_securitySettings = options.Value;
_userRepo = userRepo;
}
}
然后我们要在 AuthService 里实现
- 生成token
- 从数据库获取用户
- 从token里取出用户信息
这几个功能
一个个来
生成token
首先是生成token,代码如下
public LoginToken GenerateLoginToken(User user) {
var claims = new List<Claim> {
new("username", user.Name),
new(JwtRegisteredClaimNames.Name, user.Id), // User.Identity.Name
new(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()), // JWT ID
};
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_securitySettings.Token.Key));
var signCredential = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var jwtToken = new JwtSecurityToken(
issuer: _securitySettings.Token.Issuer,
audience: _securitySettings.Token.Audience,
claims: claims,
expires: DateTime.Now.AddDays(7),
signingCredentials: signCredential);
return new LoginToken {
Token = new JwtSecurityTokenHandler().WriteToken(jwtToken),
Expiration = TimeZoneInfo.ConvertTimeFromUtc(jwtToken.ValidTo, TimeZoneInfo.Local)
};
}
从数据库获取用户
代码如下
public User? GetUserById(string userId) {
return _userRepo.Where(a => a.Id == userId).ToOne();
}
public User? GetUserByName(string name) {
return _userRepo.Where(a => a.Name == name).ToOne();
}
从token里取出用户信息
因为客户端要提交token到服务端,JWT token里包含用户信息,所以我们可以直接从token里解密出用户信息,不需要访问数据库浪费IO性能。
代码如下
public User? GetUser(ClaimsPrincipal userClaim) {
var userId = userClaim.Identity?.Name;
var userName = userClaim.Claims.FirstOrDefault(c => c.Type == "username")?.Value;
if (userId == null || userName == null) return null;
return new User { Id = userId, Name = userName };
}
OK,最关键的部分完成了,接下来就是写个登录接口
登录接口
没啥东西,在 Apis 目录下新建 AuthController.cs,然后直接上代码
using Microsoft.AspNetCore.Mvc;
using StarBlog.Web.Services;
using StarBlog.Web.ViewModels;
using StarBlog.Web.ViewModels.Response;
namespace StarBlog.Web.Controllers;
[ApiController]
[Route("Api/[controller]")]
public class AuthController : ControllerBase {
private readonly AuthService _authService;
public AuthController(AuthService authService) {
_authService = authService;
}
[HttpPost]
public ApiResponse<LoginToken> Login(LoginUser loginUser) {
var user = _authService.GetUserByName(loginUser.Username);
if (user==null) return ApiResponse.NotFound(Response);
if(loginUser.Password != user.Password) return ApiResponse.Unauthorized(Response);
return new ApiResponse<LoginToken>(_authService.GenerateLoginToken(user));
}
}
哦,再加个一个获取当前登录用户信息的接口。
代码如下
[Authorize]
[HttpGet]
public ActionResult<User> GetUser() {
var user = _authService.GetUser(User);
if (user == null) return NotFound();
return user;
}
加了 [Authorize] 特性,表示这个接口需要登录才能用
swagger小绿锁
其实就是swagger的请求过滤器,配置了token之后,可以在请求的时候带上token,访问需要登录的接口。
首先要安装一个新的nuget依赖
dotnet add package Swashbuckle.AspNetCore.Filters
这个组件的项目地址:https://github.com/mattfrear/Swashbuckle.AspNetCore.Filters
为了使Program.cs的代码尽量简洁,我们依然新建一个扩展方法来放swagger的配置
在Extensions目录下新建ConfigureSwagger类
代码如下
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.Filters;
namespace StarBlog.Web.Extensions;
public static class ConfigureSwagger {
public static void AddSwagger(this IServiceCollection services) {
services.AddSwaggerGen(options => {
var security = new OpenApiSecurityScheme {
Description = "JWT模式授权,请输入 \"Bearer {Token}\" 进行身份验证",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey
};
options.AddSecurityDefinition("oauth2", security);
options.AddSecurityRequirement(new OpenApiSecurityRequirement { { security, new List<string>() } });
options.OperationFilter<AddResponseHeadersFilter>();
options.OperationFilter<AppendAuthorizeToSummaryOperationFilter>();
options.OperationFilter<SecurityRequirementsOperationFilter>();
var filePath = Path.Combine(System.AppContext.BaseDirectory, $"{typeof(Program).Assembly.GetName().Name}.xml");
options.IncludeXmlComments(filePath, true);
});
}
}
然后回到Program.cs文件,添加这行代码就行
builder.Services.AddSwagger();
_EOF_
StarBlog博客开发笔记:身份认证功能
- 本文作者:
- 程序设计实验室
- 版权声明:
- 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
相关文章
StarBlog博客开发笔记(15):生成随机尺寸图片
系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetCore开发博客项目 StarBlog - (3) 模型设计 基于.NetCore开发博客项目 StarBlog - (4) markdown博客批量导入 基于.NetCore开发博客项目 StarBl
2022-07-18 · StarBlog博客开发笔记 · 约 1 分钟
StarBlog博客开发笔记:部署
Nginx 反向代理 后端配置中间件 app.UseForwardedHeaders(new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto }); Nginx配置 server { listen
2022-12-05 · StarBlog博客开发笔记 · 约 1 分钟
StarBlog博客开发笔记(26):集成Swagger接口文档
前言 这是StarBlog系列在2023年的第一篇更新😃~ 在之前的文章里,我们已经完成了部分接口的开发,接下来需要使用 curl、Postman 这类工具对这些接口进行测试,但接口一多,每次测试都要一个个填入地址和对应参数会比较麻烦… 我们需要一种直观的方式来汇总项目里的所有接口,并且如果能直接在里面调试接口,那就更好了。 Swagger:诶嘿,说的不就是我吗?😎 Swagger介绍 来一段
2023-03-11 · StarBlog博客开发笔记 · 约 1 分钟
StarBlog博客开发笔记(22):开发博客文章相关接口
前言 本文介绍博客文章相关接口的开发,作为接口开发介绍的第一篇,会写得比较详细,以抛砖引玉,后面的其他接口就粗略带过了,着重于WebApi开发的周边设施。 涉及到的接口:文章CRUD、置顶文章、推荐文章等。 开始前先介绍下AspNetCore框架的基础概念,MVC模式(前后端不分离)、WebApi模式(前后端分离),都是有Controller的。 区别在前者的Controller集成自 Contr
2023-01-02 · StarBlog博客开发笔记 · 约 1 分钟
讨论
共 0 条加载评论中…