当前位置:网站首页>Try to build my mall from scratch (2): use JWT to protect our information security and perfect swagger configuration
Try to build my mall from scratch (2): use JWT to protect our information security and perfect swagger configuration
2020-11-06 20:13:45 【itread01】
## Preface ### GitHub Address > https://github.com/yingpanwang/MyShop/tree/dev_jwt > This paper corresponds to the branch dev_jwt ### Purpose of this article In the last article , We use Abp vNext Build a simple executable API, But there's no way for the entire site to go to our API Access is limited , Lead to API Completely naked , If you want to do normal business API It's totally impossible , So next we'll use JWT(Json Web Toekn) The way to realize to API Access restrictions for . #### JWT Introduction ###### What is JWT Now API It is generally decentralized and requires stateless , So the traditional Session Can't use ,JWT It's similar to the early days API Based on Cookie Custom user authentication form , It's just JWT The design is more compact and easy to expand the package open , It is more convenient to use because JWT The authentication mechanism of is similar to http The agreement is also stateless , It doesn't need to keep the user's authentication information or session information in the server . ###### JWT Composition of JWT ( Hereinafter referred to as Token) Its composition is divided into three parts header,playload,signature complete Token Long like this eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoid2FuZ3lpbmdwYW4iLCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjIiLCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9tb2JpbGVwaG9uZSI6IjEyMiIsImV4cCI6MTYwNDI4MzczMSwiaXNzIjoiTXlTaG9wSXNzdWVyIiwiYXVkIjoiTXlTaG9wQXVkaWVuY2UifQ.U-2bEniEz82ECibBzk6C5tuj2JAdqISpbs5VrpA8W9s **header** Contains type and algorithm information ``` JSON { "alg": "HS256", "typ": "JWT" } ``` Through base64 After encryption, you get eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 **playload** Contains standard public life and private announcements , It is not recommended to define sensitive information , Because the information can be decrypted Part of the public announcement * iss: jwt Issued by * aud: receive jwt On the side of * exp: jwt The expiration date of , This expiration time must be greater than the issuing time Private announcement * http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name : Name * http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier: Identification * http://schemas.xmlsoap.org/ws/2005/05/identity/claims/mobilephone: Telephone ``` JSON { "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name": "wangyingpan", "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier": "2", "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/mobilephone": "122", "exp": 1604283731, "iss": "MyShopIssuer", "aud": "MyShopAudience" } ``` Through base64 After encryption, you get eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoid2FuZ3lpbmdwYW4iLCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjIiLCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9tb2JpbGVwaG9uZSI6IjEyMiIsImV4cCI6MTYwNDI4MzczMSwiaXNzIjoiTXlTaG9wSXNzdWVyIiwiYXVkIjoiTXlTaG9wQXVkaWVuY2UifQ **signature** signature from Three parts of information , They are base64 Encrypted **header**,**playload** use "." Connect , Encrypted by declarative calculus Server-side **secret** As salt (**salt**) Three parts through “.” Connecting three parts makes up the final Token ## Code practice ### New user services ##### 1.Domain User entities are defined in User ``` csharp public class User:BaseGuidEntity { [Required] public string Account { get; set; } ///
/// Name /// public string NickName { get; set; } ///
/// The real name /// public string RealName { get; set; } ///
/// Age /// public int Age { get; set; } ///
/// Cell phone number /// public string Tel { get; set; } ///
/// address /// public string Address { get; set; } ///
/// code /// public string Password { get; set; } ///
/// User status /// public UserStatusEnum UserStatus { get; set; } } public enum UserStatusEnum { Registered,// Registered Incompleted, // Incomplete information Completed,// Perfect information Locked, // Lock Deleted // Delete } ``` ##### 2.EntityFrameworkCore Newly added Table **UserCreatingExtension.cs** ``` csharp public static class UserCreatingExtension { public static void ConfigureUserStore(this ModelBuilder builder) { Check.NotNull(builder, nameof(builder)); builder.Entity
(option => { option.ToTable("User"); option.ConfigureByConvention(); }); } } ``` **MyShopDbContext.cs** ``` csharp [ConnectionStringName("Default")] public class MyShopDbContext:AbpDbContext
{ public MyShopDbContext(DbContextOptions
options) : base(options) { } protected override void OnModelCreating(ModelBuilder builder) { builder.ConfigureProductStore(); builder.ConfigureOrderStore(); builder.ConfigureOrderItemStore(); builder.ConfigureCategoryStore(); builder.ConfigureBasketAndItemsStore(); // Configure user table builder.ConfigureUserStore(); } public DbSet
Products { get; set; } public DbSet
Orders { get; set; } public DbSet
OrderItems { get; set; } public DbSet
Categories { get; set; } public DbSet
Basket { get; set; } public DbSet
BasketItems { get; set; } // Add user table public DbSet
Users { get; set; } } ``` ##### 3. Migration generates User surface First add a user table definition ``` csharp [ConnectionStringName("Default")] public class DbMigrationsContext : AbpDbContext
{ public DbMigrationsContext(DbContextOptions
options) : base(options) { } protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); builder.ConfigureProductStore(); builder.ConfigureOrderStore(); builder.ConfigureOrderItemStore(); builder.ConfigureCategoryStore(); builder.ConfigureBasketAndItemsStore(); // User configuration builder.ConfigureUserStore(); } } ``` Then open the package management console and switch to the migration project **MyShop.EntityFrameworkCore.DbMigration** And type * >Add-Migration "AddUser" * >Update-Database Now User The table is already generated and corresponds to Migration Archives ##### 4.Application Build UserApplication ###### Api New configuration in AppSetting.json ``` csharp "Jwt": { "SecurityKey": "1111111111111111111111111111111", "Issuer": "MyShopIssuer", "Audience": "MyShopAudience", "Expires": 30 // Expired minutes } ``` ###### IUserApplicationService ``` csharp namespace MyShop.Application.Contract.User { public interface IUserApplicationService { Task
> Register(UserRegisterDto registerInfo, CancellationToken cancellationToken); Task
> Login(UserLoginDto loginInfo); } } ``` ###### AutoMapper Profiles A new pair of images has been added in ``` csharp namespace MyShop.Application.AutoMapper.Profiles { public class MyShopApplicationProfile:Profile { public MyShopApplicationProfile() { CreateMap
().ReverseMap(); CreateMap
().ReverseMap(); CreateMap
().ReverseMap(); CreateMap
().ReverseMap(); CreateMap
().ReverseMap(); // User registration information mapping CreateMap
() .ForMember(src=>src.UserStatus ,opt=>opt.MapFrom(src=> UserStatusEnum.Registered)) .ForMember(src=>src.Password , opt=>opt.MapFrom(src=> EncryptHelper.MD5Encrypt(src.Password,string.Empty))); } } } ``` ###### UserApplicationService ``` csharp namespace MyShop.Application { ///
/// User services /// public class UserApplicationService : ApplicationService, IUserApplicationService { private readonly IConfiguration _configuration; private readonly IRepository
_userRepository; ///
/// Structure /// ///
User storage ///
Configuration information public UserApplicationService(IRepository
userRepository, IConfiguration configuration) { _userRepository = userRepository; _configuration = configuration; } ///
/// Log in /// ///
Login information ///
public async Task
> Login(UserLoginDto loginInfo) { if (string.IsNullOrEmpty(loginInfo.Account) || string.IsNullOrEmpty(loginInfo.Password)) return BaseResult
.Failed(" User name password cannot be empty !"); var user = await Task.FromResult(_userRepository.FirstOrDefault(p => p.Account == loginInfo.Account)); if (user == null) { return BaseResult
.Failed(" User name password error !"); } string md5Pwd = EncryptHelper.MD5Encrypt(loginInfo.Password); if (user.Password != md5Pwd) { return BaseResult
.Failed(" User name password error !"); } var claims = GetClaims(user); var token = GenerateToken(claims); return BaseResult
.Success(token); } ///
/// Register /// ///
Registration information ///
Cancel the token ///
public async Task
> Register(UserRegisterDto registerInfo,CancellationToken cancellationToken) { var user = ObjectMapper.Map
(registerInfo); var registeredUser = await _userRepository.InsertAsync(user, true, cancellationToken); var claims = GetClaims(user); var token = GenerateToken(claims); return BaseResult
.Success(token); } #region Token Generate private IEnumerable
GetClaims(User user) { var claims = new[] { new Claim(AbpClaimTypes.UserName,user.NickName), new Claim(AbpClaimTypes.UserId,user.Id.ToString()), new Claim(AbpClaimTypes.PhoneNumber,user.Tel), new Claim(AbpClaimTypes.SurName, user.UserStatus == UserStatusEnum.Completed ?user.RealName:string.Empty) }; return claims; } ///
/// Generate token /// ///
Declare ///
private TokenInfo GenerateToken(IEnumerable
claims) { // Key var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Jwt:SecurityKey"])); var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); // Expiration time int expires = string.IsNullOrEmpty(_configuration["Expires"]) ? 30 : Convert.ToInt32(_configuration["Expires"]); // Generate token var token = new JwtSecurityToken( issuer: _configuration["Jwt:Issuer"], audience: _configuration["Jwt:Audience"], claims: claims, expires: DateTime.Now.AddMinutes(expires), signingCredentials: creds); return new TokenInfo() { Expire = expires, Token = new JwtSecurityTokenHandler().WriteToken(token) }; } #endregion } } ``` ### Enable authentication and add related Swagger To configure Add the following code to the site module that needs to start Authentication (MyShopApiModule) ###### MyShopApiModule.cs ``` csharp using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.PlatformAbstractions; using Microsoft.IdentityModel.Tokens; using Microsoft.OpenApi.Models; using MyShop.Admin.Application; using MyShop.Admin.Application.Services; using MyShop.Api.Middleware; using MyShop.Application; using MyShop.Application.Contract.Order; using MyShop.Application.Contract.Product; using MyShop.EntityFrameworkCore; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using Volo.Abp; using Volo.Abp.AspNetCore; using Volo.Abp.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc.Conventions; using Volo.Abp.AspNetCore.Mvc.ExceptionHandling; using Volo.Abp.Autofac; using Volo.Abp.Modularity; namespace MyShop.Api { // Attention depends on AspNetCoreMvc instead of AspNetCore [DependsOn(typeof(AbpAspNetCoreMvcModule),typeof(AbpAutofacModule))] [DependsOn(typeof(MyShopApplicationModule),typeof(MyShopEntityFrameworkCoreModule),typeof(MyShopAdminApplicationModule))] public class MyShopApiModule :AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) { var service = context.Services; // To configure jwt ConfigureJwt(service); // Configure cross domain ConfigureCors(service); // To configure swagger ConfigureSwagger(service); service.Configure((AbpAspNetCoreMvcOptions options) => { options.ConventionalControllers.Create(typeof(Application.ProductApplicationService).Assembly); options.ConventionalControllers.Create(typeof(Application.OrderApplicationService).Assembly); options.ConventionalControllers.Create(typeof(Application.UserApplicationService).Assembly); options.ConventionalControllers.Create(typeof(Application.BasketApplicationService).Assembly); options.ConventionalControllers.Create(typeof(Admin.Application.Services.ProductApplicationService).Assembly, options => { options.RootPath = "admin"; }); }); } public override void OnApplicationInitialization(ApplicationInitializationContext context) { var env = context.GetEnvironment(); var app = context.GetApplicationBuilder(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } // Cross domain app.UseCors("AllowAll"); // swagger app.UseSwagger(); app.UseSwaggerUI(options => { options.SwaggerEndpoint("/swagger/v1/swagger.json", "MyShopApi"); }); app.UseRouting(); // newly added jwt Verification Be careful : You must add authentication first, and then add authorized intermediary software , And must be added in UseRouting and UseEndpoints Between app.UseAuthentication(); app.UseAuthorization(); app.UseConfiguredEndpoints(); } #region ServicesConfigure private void ConfigureJwt(IServiceCollection services) { var configuration = services.GetConfiguration(); services .AddAuthentication(options=> { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(options=> { options.RequireHttpsMetadata = false;// The development environment is false options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters() { ValidateIssuer = true,// Whether to verify Issuer ValidateAudience = true,// Whether to verify Audience ValidateLifetime = true,// Whether to verify the expiration time ClockSkew = TimeSpan.FromSeconds(30), // Offset time , So the actual expiration time = Given the expiration time + Offset time ValidateIssuerSigningKey = true,// Whether to verify SecurityKey ValidAudience = configuration["Jwt:Audience"],//Audience ValidIssuer = configuration["Jwt:Issuer"],//Issuer, These two items and the previous issue jwt The settings are consistent IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["Jwt:SecurityKey"]))// Get SecurityKey }; // event options.Events = new JwtBearerEvents() { OnAuthenticationFailed = context => { return Task.CompletedTask; }, OnChallenge = context => { // Validation failed BaseResult
版权声明
本文为[itread01]所创,转载请带上原文链接,感谢
边栏推荐
- C++ 数字、string和char*的转换
- C++学习——centos7上部署C++开发环境
- C++学习——一步步学会写Makefile
- C++学习——临时对象的产生与优化
- C++学习——对象的引用的用法
- C++编程经验(6):使用C++风格的类型转换
- Won the CKA + CKS certificate with the highest gold content in kubernetes in 31 days!
- C + + number, string and char * conversion
- C + + Learning -- capacity() and resize() in C + +
- C + + Learning -- about code performance optimization
猜你喜欢
-
C + + programming experience (6): using C + + style type conversion
-
Latest party and government work report ppt - Park ppt
-
在线身份证号码提取生日工具
-
Online ID number extraction birthday tool
-
️野指针?悬空指针?️ 一文带你搞懂!
-
Field pointer? Dangling pointer? This article will help you understand!
-
HCNA Routing&Switching之GVRP
-
GVRP of hcna Routing & Switching
-
Seq2Seq实现闲聊机器人
-
【闲聊机器人】seq2seq模型的原理
随机推荐
- LeetCode 91. 解码方法
- Seq2seq implements chat robot
- [chat robot] principle of seq2seq model
- Leetcode 91. Decoding method
- HCNA Routing&Switching之GVRP
- GVRP of hcna Routing & Switching
- HDU7016 Random Walk 2
- [Code+#1]Yazid 的新生舞会
- CF1548C The Three Little Pigs
- HDU7033 Typing Contest
- HDU7016 Random Walk 2
- [code + 1] Yazid's freshman ball
- CF1548C The Three Little Pigs
- HDU7033 Typing Contest
- Qt Creator 自动补齐变慢的解决
- HALCON 20.11:如何处理标定助手品质问题
- HALCON 20.11:标定助手使用注意事项
- Solution of QT creator's automatic replenishment slowing down
- Halcon 20.11: how to deal with the quality problem of calibration assistant
- Halcon 20.11: precautions for use of calibration assistant
- “十大科学技术问题”揭晓!|青年科学家50²论坛
- "Top ten scientific and technological issues" announced| Young scientists 50 ² forum
- 求反转链表
- Reverse linked list
- js的数据类型
- JS data type
- 记一次文件读写遇到的bug
- Remember the bug encountered in reading and writing a file
- 单例模式
- Singleton mode
- 在这个 N 多编程语言争霸的世界,C++ 究竟还有没有未来?
- In this world of N programming languages, is there a future for C + +?
- es6模板字符
- js Promise
- js 数组方法 回顾
- ES6 template characters
- js Promise
- JS array method review
- 【Golang】️走进 Go 语言️ 第一课 Hello World
- [golang] go into go language lesson 1 Hello World