如何使用 ASP.NET Core 創建基于角色的 Web API

在使用 ASP.NET Core 構建基于角色的 Web API 時,代碼優先方法是一種強大而高效的方法。使用它,我們可以在代碼中定義數據模型和關系,然后自動生成相應的數據庫模式。這會帶來什么?當然是更快的開發周期和更大的靈活性。為什么?因為可以快速輕松地更改數據模型,而無需直接修改數據庫模式。?您可以在 swagger.io 上閱讀有關設計優先和代碼優先方法的更多信息。

在本教程中,我們將介紹使用 ASP.NET Core 6 創建基于角色的 Web API 的步驟。我們將使用 Swagger UI 來可視化并與我們的端點以及作為數據庫的 MS SQL Server 進行交互。該應用程序將包含一個身份驗證模塊和一個事件模塊。登錄用戶將能夠查看與其帳戶關聯的事件,而具有管理員角色的用戶可以創建、更新和刪除事件。

示例下載:https://download.csdn.net/download/hefeng_aspnet/91490040??

讓我們開始吧!

項目設置

首先,我們需要設置項目。打開 Visual Studio,創建一個新項目,然后選擇 ASP.NET Core Web API。

選擇應用程序的名稱,然后單擊“下一步”。

設置 API 數據庫

初始化應用程序后,我們需要配置數據庫。我們將使用?EntityFrameworkCore?作為?ORM??,以便它幫助我們管理數據庫。因此,我們需要安裝一些軟件包。

成功安裝軟件包后,下一步要做的是創建?DbContext。創建?DataContext.cs?文件并繼承?DBContext?類。在這里我們將定義表。

public class DataContext: DbContext
{
? public DataContext(DbContextOptions options): base(options)
? {
? }

? //Define our tables
}

然后,我們打開 Program.cs 文件并添加 dbContext。我們需要指定 ?來自 appsettings.json 文件的 dbProvider和連接字符串。 dbProvider 可以是 SqlServer、MySql 或 InMemory。

// Add Db context

var dbProvider = builder.Configuration.GetConnectionString("Provider");

builder.Services.AddDbContext < DataContext > (options =>
? {

? ? if (dbProvider == "SqlServer")
? ? {
? ? ? options.UseSqlServer(builder.Configuration.GetConnectionString("SqlServerConnectionString"));
? ? }
? });

確保已 ?在 appsettings.json文件中添加了ConnectionString 和 Provider ?,如下所示:


"ConnectionStrings": {
? "Provider": "SqlServer",
? "SqlServerConnectionString": "Data Source=(localdb)\\MSSQLLocalDB;Database=HRApplication2;Integrated Security=True;Connect Timeout=30; "
},

配置 DbContext后,需要生成數據庫模型。在本例中,我們需要兩個實體(User 和 Event)以及第三個表(UserEvent)來建立它們之間的多對多關系。為此,建議創建一個 Models 文件夾,并在其中創建一個 DbModels 子文件夾,用于創建數據庫實體。

讓我們從 用戶 模型開始。每個用戶都應該有一個唯一的 ID、電子郵件、名字、姓氏、密碼(將以哈希格式存儲)、角色(在演示中可以是用戶或管理員)以及 與UserEvent表 關聯的 UserEvents ?。

public class User
{
? ? public string UserId { get; set; }
? ? public string Email { get; set; }
? ? public string FirstName { get; set; }
? ? public string LastName { get; set; }
? ? public string Password { get; set; }
? ? public string Role { get; set; }
? ? public IList <UserEvent> UserEvents { get; set; }
}

事件模型還應具有唯一的 ID、標題、類別、日期以及與 UserEvents 表的關系。

public class Event
{
? ? public string Id { get; set; }
? ? public string Title { get; set; }
? ? public string Category { get; set; }
? ? public DateTime Date { get; set; }
? ? public IList <UserEvent> UserEvents { get; set; }
}

由于一個用戶可以參加多個活動,并且一個活動也可以由多個用戶參加,因此我們需要在這些實體之間建立多對多關系。為此,我們將創建一個名為 UserEvents的附加表。該表將包含 UserId 和 EventId列,用于建立用戶實體 和 事件實體 之間的關系 ?。

public class UserEvent
{
? ? public string UserId { get; set; }
? ? public User User { get; set; }
? ? public string EventId { get; set; }
? ? public Event Event { get; set; }
}

創建數據庫模型后,下一步就是在 DbContext中注冊它們。為此,我們可以導航到 DataContext.cs 文件,將所有實體添加為 DbSets,并聲明關系和主鍵。這可以通過重寫 OnModelCreating 方法并使用 Fluent API 配置關系和鍵來實現。完成后,結果應如下所示:

public class DataContext: DbContext
{
? public DataContext(DbContextOptions options): base(options)
? {
? }
??
? public DbSet <User> Users { get; set; }
? public DbSet < Event > Events { get; set; }
? public DbSet < UserEvent > UserEvents { get; set; }

? protected override void OnModelCreating(ModelBuilder builder)
? {
? ? base.OnModelCreating(builder);

? ? builder.Entity<User>()
? ? ? .HasKey(u => new {
? ? ? ? u.UserId
? ? ? });

? ? builder.Entity<Event>()
? ? ? .HasKey(e => new {
? ? ? ? e.Id
? ? ? });

? ? builder.Entity<UserEvent>()
? ? ? .HasKey(ue => new {
? ? ? ? ue.UserId, ue.EventId
? ? ? });

? ? builder.Entity<UserEvent>()
? ? ? .HasOne(ue => ue.User)
? ? ? .WithMany(user => user.UserEvents)
? ? ? .HasForeignKey(u => u.UserId);

? ? builder.Entity<UserEvent>()
? ? ? .HasOne(uc => uc.Event)
? ? ? .WithMany(ev => ev.UserEvents)
? ? ? .HasForeignKey(ev => ev.EventId);
? }
}

在我們準備好數據庫設計之后,我們應該生成一個將創建數據庫的初始遷移。

打開包管理器控制臺 并寫入命令:

添加遷移初始創建

成功執行后,我們應該使用以下命令更新數據庫:

更新數據庫

然后使用 Microsoft SQL Management Studio,您應該會看到新創建的數據庫。

配置 AutoMapper

AutoMapper?會幫助我們將一個模型轉換為另一個模型。這會將輸入模型轉換為?dbModel。?我們這樣做的原因是,我們可能不需要將一個模型的所有屬性都包含在另一個模型中。您將在本教程的后面部分看到我們如何使用 AutoMapper。在此之前,我們需要先配置它。?您可以在官方文檔中找到更多關于 AutoMapper 的詳細說明。?

首先,我們必須安裝 AutoMaper NuGet 包。之后,我們可以生成一個?MappingProfiles.cs?文件來定義所有映射。為了便于組織,建議將此文件創建在 Helpers 文件夾下。

為了聲明映射,??MappingProfiles?應該繼承 Profile 類,并且我們可以使用?CreateMap<from, to>()?方法聲明映射。如果我們需要反向映射模型,可以添加?.ReverseMap()?方法。

一旦我們完成映射,我們必須導航到?Program.cs?文件并??使用我們的?MappingProfiles注冊AutoMapper

…
var config = new MapperConfiguration(cfg =>{cfg.AddProfile(new MappingProfiles());});var mapper = config.CreateMapper();builder.Services.AddSingleton(mapper);
…?

設置身份驗證

我們將使用?JWT?令牌進行身份驗證。它們為我們提供了一種以 JSON 對象形式在各方之間安全地傳輸信息的方法。您可以?在此處閱讀有關 JWT 令牌的更多信息。要使用它們,我們必須首先安裝必要的 NuGet 包。我們需要?Microsoft.IdentityModel.Tokens?和?Microsoft.AspNetCore.Authentication.JwtBearer

接下來,我們必須在appsettings.json 文件中定義一些 token 配置?。這些配置包括 Issuer、Audience 和 SecretKey。

"Jwt": {"Issuer": "https://localhost:7244/","Audience": "https://localhost:7244/","Key": "S1u*p7e_r+S2e/c4r6e7t*0K/e7y"
}

定義令牌配置后,我們可以在?Program.cs?文件中配置 JWT 服務。這涉及指定將使用的架構以及任何必要的驗證參數。?

…
builder.Services.AddAuthentication(options =>{options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;}).AddJwtBearer(o =>{o.TokenValidationParameters = new TokenValidationParameters{ValidIssuer = builder.Configuration["Jwt:Issuer"],ValidAudience = builder.Configuration["Jwt:Audience"],IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"])),ValidateIssuer = true,ValidateAudience = true,ValidateLifetime = false,ValidateIssuerSigningKey = true};});
…

確保您還添加了?app.UseAuthentication();

設置Swagger

為了使用?Swagger UI測試我們的應用程序端點,我們必須??在?Program.cs文件中包含app.UseSwaggerUI()??。

之后,我們必須生成一個?AuthResponse?過濾器,以便使用 JWT 令牌測試已驗證的端點。為此,我們可以創建一個??實現?IOperationFilter接口的AuthResponsesOperationFilter類?。Apply 方法應該包含將?AuthResponse?過濾器添加到 Swagger 所需的邏輯。

public class AuthResponsesOperationFilter: IOperationFilter
{public void Apply(OpenApiOperation operation, OperationFilterContext context){var authAttributes = context.MethodInfo.DeclaringType.GetCustomAttributes(true).Union(context.MethodInfo.GetCustomAttributes(true)).OfType<AuthorizeAttribute>();if (authAttributes.Any()){var securityRequirement = new OpenApiSecurityRequirement(){{new OpenApiSecurityScheme{Reference = new OpenApiReference{Type = ReferenceType.SecurityScheme,Id = "Bearer"}},new List<string>()}};operation.Security = new List<OpenApiSecurityRequirement> {securityRequirement};operation.Responses.Add("401", new OpenApiResponse {Description = "Unauthorized"});}}
}

之后,確保已在?Program.cs??.AddSwaggerGen?方法中將過濾器添加為選項。?

builder.Services.AddSwaggerGen(option =>{option.SwaggerDoc("v1", new OpenApiInfo {Title = "Northwind CRUD", Version = "v1"});option.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme{In = ParameterLocation.Header,Description = "Please enter a valid token",Name = "Authorization",Type = SecuritySchemeType.Http,BearerFormat = "JWT",Scheme = "bearer"});option.OperationFilter < AuthResponsesOperationFilter > ();});

您可以在官方文檔中閱讀“什么是 Swagger?”的更詳細解釋?。

注冊端點

完成配置后,我們可以繼續創建注冊端點。第一步是生成一個?RegisterInputModel.cs?文件,該文件位于?Models/InputModels?文件夾下。

注冊過程需要 Email、FirstName、LastName、Password 和 ConfirmedPassword 字段。所有這些字段都是必填項,因此我們將添加?[Required]?屬性。此外,我們還將為 Email 字段添加?[EmailAddress]?屬性。我們可以根據需要添加其他屬性,例如最小長度和最大長度。但出于演示目的,我們將僅使用這些屬性。

public class RegisterInputModel
{[EmailAddress]public string Email { get; set; }[Required]public string FirstName { get; set; }[Required]public string LastName { get; set; }[Required]public string Password { get; set; }[Required]public string ConfirmedPassword { get; set; }
}

接下來,我們必須向MappingProfiles.cs文件添加一個映射?,以便在RegisterInputModel?和?User模型?之間實現??雙向轉換。

創建映射<RegisterInputModel,用戶>().ReverseMap();

為了保持關注點分離,我們將創建一個 Services 文件夾。每個模塊都有自己的服務用于與數據庫交互。我們可以先生成一個?AuthService.cs?文件,并注入?DataContext?和?Configuration

AuthService.cs中的第一個方法??應該是?GenerateJwtToken,它將電子郵件和角色作為參數并返回包含用戶信息的 JWT 令牌。

public string GenerateJwtToken(string email, string role)
{var issuer = this.configuration["Jwt:Issuer"];var audience = this.configuration["Jwt:Audience"];var key = Encoding.ASCII.GetBytes(this.configuration["Jwt:Key"]);var tokenDescriptor = new SecurityTokenDescriptor{Subject = new ClaimsIdentity(new []{new Claim("Id", Guid.NewGuid().ToString()),new Claim(JwtRegisteredClaimNames.Sub, email),new Claim(JwtRegisteredClaimNames.Email, email),new Claim(ClaimTypes.Role, role),new Claim(JwtRegisteredClaimNames.Jti,Guid.NewGuid().ToString())}),Expires = DateTime.UtcNow.AddMinutes(5),Issuer = issuer,Audience = audience,SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha512Signature)};var tokenHandler = new JwtSecurityTokenHandler();var token = tokenHandler.CreateToken(tokenDescriptor);return tokenHandler.WriteToken(token);
}

為了對密碼進行哈希處理,我們將使用?BCrypt.Net.BCrypt。首先,我們必須安裝該包并將其作為 using 語句添加到文件開頭。

using BC = BCrypt.Net.BCrypt;

之后,我們將創建幾個輔助方法。其中一個將驗證具有給定電子郵件的用戶是否存在,另一個將對用戶進行身份驗證,另外兩個將通過電子郵件和 ID 獲取用戶。

public bool IsAuthenticated(string email, string password)
{var user = this.GetByEmail(email);return this.DoesUserExists(email) && BC.Verify(password, user.Password);
}public bool DoesUserExists(string email)
{var user = this.dataContext.Users.FirstOrDefault(x => x.Email == email);return user != null;
}public User GetById(string id)
{return this.dataContext.Users.FirstOrDefault(c => c.UserId == id);
}public User GetByEmail(string email)
{return this.dataContext.Users.FirstOrDefault(c => c.Email == email);
}

在創建register方法之前,我們必須先創建一個方法來生成唯一的ID。該方法可以定義如下:?

public class IdGenerator
{public static string CreateLetterId(int length){var random = new Random();const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";return new string(Enumerable.Repeat(chars, length).Select(s => s[random.Next(s.Length)]).ToArray());}
}

現在我們可以繼續實現 Register 方法了。在這個方法中,我們將生成一個唯一的 ID,檢查它是否已經存在,如果存在,則生成一個新的。然后,我們將對用戶密碼進行哈希處理,并將新用戶添加到數據庫中。?

public User RegisterUser(User model)
{var id = IdGenerator.CreateLetterId(10);var existWithId = this.GetById(id);while (existWithId != null){id = IdGenerator.CreateLetterId(10);existWithId = this.GetById(id);}model.UserId = id;model.Password = BC.HashPassword(model.Password);var userEntity = this.dataContext.Users.Add(model);this.dataContext.SaveChanges();return userEntity.Entity;
}

如果您尚未創建?AuthController??,現在是時候了。轉到?Controllers?文件夾并添加?AuthController??,它應該繼承自 Controller 類。我們還應該添加?[ApiController]?屬性和?[Route(?“[controller]”?)]??,以便 Swagger 識別它。

之后,我們應該注入 mapper、authService 和 logger(如果使用的話),并創建 RegisterMethod。它應該只允許未經身份驗證的用戶通過 post 請求訪問。它應該接受?RegisterInputModel?作為參數,并檢查?ModelState是否?有效。如果有效,它將為該用戶生成 JWT 令牌。整個方法應該如下所示:

[AllowAnonymous]
[HttpPost("Register")]
public ActionResult<string> Register(RegisterInputModel userModel)
{try{if (ModelState.IsValid){if (userModel.Password != userModel.ConfirmedPassword){return BadRequest("Passwords does not match!");}if (this.authService.DoesUserExists(userModel.Email)){return BadRequest("User already exists!");}var mappedModel = this.mapper.Map<RegisterInputModel, User>(userModel);mappedModel.Role = "User";var user = this.authService.RegisterUser(mappedModel);if (user != null){var token = this.authService.GenerateJwtToken(user.Email, mappedModel.Role);return Ok(token);}return BadRequest("Email or password are not correct!");}return BadRequest(ModelState);} catch (Exception error){logger.LogError(error.Message);return StatusCode(500);}
}

登錄功能

登錄功能類似,只是我們需要在數據庫中搜索用戶。首先,我們應該創建?LoginInputModel.cs?文件,該文件只包含 Email 和 Password 字段。別忘了在?MappingProfiles.cs文件中添加該文件?,否則將無法正常工作。?

public class LoginInputModel
{[EmailAddress][Required]public string Email { get; set; }[Required]public string Password { get; set; }
}

然后在?AuthController.cs中?創建 Login 方法,該方法接受?LoginInputModel?作為參數,并檢查用戶是否已通過身份驗證。如果已通過身份驗證,則生成一個 token。否則,返回錯誤。?

[AllowAnonymous]
[HttpPost("Login")]
public ActionResult <string> Login(LoginInputModel userModel)
{try{if (ModelState.IsValid){if (this.authService.IsAuthenticated(userModel.Email, userModel.Password)){var user = this.authService.GetByEmail(userModel.Email);var token = this.authService.GenerateJwtToken(userModel.Email, user.Role);return Ok(token);}return BadRequest("Email or password are not correct!");}return BadRequest(ModelState);} catch (Exception error){logger.LogError(error.Message);return StatusCode(500);}
}

為事件添加 CRUD

完成身份驗證后,我們可以開發事件的端點。我們將創建完整的 CRUD 操作。與用戶操作類似,我們應該創建?EventService.cs?文件。該文件將包含以下方法:通過 ID 獲取事件、獲取特定用戶的所有事件、創建新事件、更新現有事件以及刪除事件。整個文件應如下所示:

public class EventService
{private readonly DataContext dataContext;public EventService(DataContext dataContext){this.dataContext = dataContext;}public Event[] GetAllForUser(string email){var user = this.dataContext.Users.FirstOrDefault(user => user.Email == email);return this.dataContext.Events.Include(ev => ev.UserEvents).Where(e => e.UserEvents.FirstOrDefault(ue => ue.UserId == user.UserId) != null).ToArray();}public Event GetById(string id){return this.dataContext.Events.Include(ev => ev.UserEvents).FirstOrDefault(c => c.Id == id);}public Event Create(Event model){var id = IdGenerator.CreateLetterId(6);var existWithId = this.GetById(id);while (existWithId != null){id = IdGenerator.CreateLetterId(6);existWithId = this.GetById(id);}model.Id = id;var eventEntity = this.dataContext.Events.Add(model);this.dataContext.SaveChanges();return eventEntity.Entity;}public Event Update(Event model){var eventEntity = this.dataContext.Events.Include(ev => ev.UserEvents).FirstOrDefault(c => c.Id == model.Id);if (eventEntity != null){eventEntity.Title = model.Title != null ? model.Title : eventEntity.Title;eventEntity.Date = model.Date != null ? model.Date : eventEntity.Date;eventEntity.Category = model.Category != null ? model.Category : eventEntity.Category;eventEntity.UserEvents = model.UserEvents.Count! > 0 ? model.UserEvents : eventEntity.UserEvents;this.dataContext.SaveChanges();}return eventEntity;}public Event Delete(string id){var eventEntity = this.GetById(id);if (eventEntity != null){this.dataContext.Events.Remove(eventEntity);this.dataContext.SaveChanges();}return eventEntity;}
}

接下來,您將需要轉到控制器并為每個請求設置一個方法。

我們將創建一個?EventBindingModel??,用于存儲來自事件模型的所有必要數據。

對于?GetAll?方法,確保它使用?GET?請求并檢索用戶的令牌、對其進行解碼并獲取該用戶的事件。

[HttpGet]
[Authorize]
public ActionResult<EventBindingModel[]> GetAll()
{try{var userEmail = this.authService.DecodeEmailFromToken(this.Request.Headers["Authorization"]);var events = this.eventService.GetAllForUser(userEmail);return Ok(this.mapper.Map<Event[], EventBindingModel[]> (events));} catch (Exception error){logger.LogError(error.Message);return StatusCode(500);}
}…
public string DecodeEmailFromToken(string token)
{var decodedToken = new JwtSecurityTokenHandler();var indexOfTokenValue = 7;var t = decodedToken.ReadJwtToken(token.Substring(indexOfTokenValue));return t.Payload.FirstOrDefault(x => x.Key == "email").Value.ToString();
}
…

通過id獲取也應該是以??id作為參數的GET請求。?

[HttpGet("{id}")]
[Authorize]
public ActionResult<Event> GetById(string id)
{try{var eventEntity = this.eventService.GetById(id);if (eventEntity != null){return Ok(eventEntity);}return NotFound();} catch (Exception error){logger.LogError(error.Message);return StatusCode(500);}
}

刪除端點將是?DELETE?請求,并且將以 id 作為參數。?

[HttpDelete("{id}")]
[Authorize(Roles = "Administrator")]
public ActionResult<Event> Delete(string id)
{try{var eventEntity = this.eventService.Delete(id);if (eventEntity != null){return Ok(eventEntity);}return NotFound();} catch (Exception error){logger.LogError(error.Message);return StatusCode(500);}
}

為了簡化添加或更新事件記錄的流程,我們創建一個?專門用于創建和更新操作的EventInputModel??。此模型僅需要我們提供用戶事件的必要屬性,包括標題、類別、日期、用戶 ID 和事件 ID。使用此模型,我們無需為每個操作指定?事件?模型的所有屬性。?

[HttpPost]
public ActionResult<Event> Create(EventInputModel model)
{try{if (ModelState.IsValid){var mappedModel = this.mapper.Map < EventInputModel,Event > (model);var eventEntity = this.eventService.Create(mappedModel);return Ok(eventEntity);}return BadRequest(ModelState);} catch (Exception error){logger.LogError(error.Message);return StatusCode(500);}
}

更新將是?PUT?請求,并且還將以?EventInputModel?作為參數。?

[HttpPut]
public ActionResult<Event> Update(EventInputModel model)
{try{if (ModelState.IsValid){var mappedModel = this.mapper.Map<EventInputModel, Event>(model);var eventEntity = this.eventService.Update(mappedModel);if (eventEntity != null){return Ok(eventEntity);}return NotFound();}return BadRequest(ModelState);} catch (Exception error){logger.LogError(error.Message);return StatusCode(500);}
}

添加基于角色的授權

為了將某些操作限制為特定用戶角色,我們可以使用基于角色的授權。例如,在我們的場景中,我們希望將事件的創建、更新和刪除端點的訪問權限限制為具有管理員角色的用戶。

要進行設置,我們需要?在Program.cs文件?中?添加app.UseAuthorization();??。然后,對于每個需要限制訪問的端點,我們將添加 [Authorize] 屬性,該屬性將指定允許的角色。例如,我們可以確保只有管理員才能訪問 Delete 端點。

…
[Authorize(Roles = "Administrator")]
public ActionResult<Event> Delete(string id)
…

創建 DbSeeder

在運行應用程序時,我們經常希望在數據庫中預先填充一些數據,無論是出于測試目的還是其他原因。這時就需要使用種子功能了。首先,我們需要定義要使用的數據。

為此,我們可以創建一個 Resources 文件夾并添加兩個 JSON 文件:一個用于用戶,一個用于事件。這些文件應包含我們想要填充到數據庫中的數據。例如,我們的文件可能如下所示:

[{"UserId": "USERABCDE","FirstName": "Kate","LastName": "Lorenz","Password": "kate.lorenz","Email": "klorenz@hrcorp.com","Role": "Administrator"},{"UserId": "ASERABCDE","FirstName": "Anthony","LastName": "Murray","Password": "anthony.murray","Email": "amurray@hrcorp.com","Role": "User"}
]

接下來,我們應該創建一個?包含 Seed 方法的DbSeeder?類。此方法將讀取我們之前定義的數據并將其填充到數據庫中。為此,我們需要將?dbContext?作為參數傳入。?

public class DBSeeder
{public static void Seed(DataContext dbContext){ArgumentNullException.ThrowIfNull(dbContext, nameof(dbContext));dbContext.Database.EnsureCreated();var executionStrategy = dbContext.Database.CreateExecutionStrategy();executionStrategy.Execute(() => {using(var transaction = dbContext.Database.BeginTransaction()){try{// Seed Usersif (!dbContext.Users.Any()){var usersData = File.ReadAllText("./Resources/users.json");var parsedUsers = JsonConvert.DeserializeObject <User[]>(usersData);foreach(var user in parsedUsers){user.Password = BC.HashPassword(user.Password);}dbContext.Users.AddRange(parsedUsers);dbContext.SaveChanges();}// Seed Eventsif (!dbContext.Events.Any()){var eventsData = File.ReadAllText("./Resources/events.json");var parsedEvents = JsonConvert.DeserializeObject <Event[]>(eventsData);dbContext.Events.AddRange(parsedEvents);dbContext.SaveChanges();}transaction.Commit();} catch (Exception ex){transaction.Rollback();}}});}
}

之后,在我們的?Helpers?文件夾中,我們應該創建一個數據庫初始化程序擴展,它將運行?Seed?方法。?

public static class DBInitializerExtension
{public static IApplicationBuilder UseSeedDB(this IApplicationBuilder app){ArgumentNullException.ThrowIfNull(app, nameof(app));using var scope = app.ApplicationServices.CreateScope();var services = scope.ServiceProvider;var context = services.GetRequiredService < DataContext > ();DBSeeder.Seed(context);return app;}
}?

最后,我們需要打開?Program.cs?文件并添加?app.UseSeedDB()?方法。這確保我們的應用程序啟動時會檢查數據庫中是否有數據。如果沒有,我們之前創建的 Seed 方法將自動使用我們定義的數據填充它。?

添加 CORS

為了為我們的端點啟用跨域資源共享(CORS),我們需要在?Program.cs?文件中添加一個 cors 服務。在這種情況下,我們將允許從任何區域訪問,但如果您愿意,也可以指定特定的域。

builder.Services.AddCors(policyBuilder =>policyBuilder.AddDefaultPolicy(policy =>policy.WithOrigins("*").AllowAnyHeader().AllowAnyHeader())
);

然后添加?app.UseCors();?方法。

這將允許我們從前端應用程序訪問我們的 API。

您可以在此處閱讀有關跨域資源共享(CORS)的更多信息。

總結一下……

在構建安全且可擴展的 Web 應用程序時,使用 ASP .NET Core 創建基于角色的 API 至關重要。通過使用基于角色的授權,您可以根據分配給用戶的角色來控制對 API 資源的訪問。這確保只有授權用戶才能訪問敏感數據或執行關鍵操作,從而使您的應用程序更加安全可靠。在本教程中,我們學習了如何從零到一創建一個簡單的基于角色的 API。

示例下載:https://download.csdn.net/download/hefeng_aspnet/91490040?

如果您喜歡此文章,請收藏、點贊、評論,謝謝,祝您快樂每一天。?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/95500.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/95500.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/95500.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

無字母數字命令執行

寫在前面 說白了數字還是好構造的&#xff0c;bash的算數拓展&#xff01; base64命令 這玩意說白了有點雞肋&#xff0c;因為你得知道flag的文件名和位置&#xff01; base64 flag.php這個會將flag.php里面的內容給base64編碼輸出來。那么如何用無字母數字構造呢&#xff1f; …

AAB包轉apks轉apk

1. 下載bundletool-all-1.17.2.jar&#xff08;不一定非得1.17.2&#xff0c;可以其他版本&#xff09; https://github.com/google/bundletool/releases/tag/1.17.2 2. 在aab、keystore、bundletool-all-1.17.2.jar的目錄下&#xff0c;運行指令 java -jar bundletool-all-1…

從零開始:用uv構建并發布一個Python CLI應用,集成CI/CD自動化發布與Docker容器化部署

使用uv構建并發布一個完整的Python CLI應用 概述 初始化項目 編寫應用代碼 定義項目 (`pyproject.toml`) 使用`uv`安裝依賴 本地運行和測試 依賴鎖定 構建 發布 生產環境實踐之CI/CD 創建工作流配置文件 配置GitHub Secrets 創建和推送tag 驗證發布 生產環境實踐之Docker 創建D…

如何在Qt中使用周立功USB轉CAN卡

如何在 Qt 中使用周立功 USB 轉 CAN 卡 文章目錄如何在 Qt 中使用周立功 USB 轉 CAN 卡一、簡介二、準備工作三、使用四、運行效果五、寫在最后?一、簡介 最近在工程中用到了周立功的 USB 轉 CAN 卡&#xff0c;需求是要通過上位機進行通信&#xff0c;因此有了這篇文章。 有…

JavaScript 源碼剖析:從字節碼到執行的奇妙旅程

JavaScript&#xff0c;這門風靡全球的腳本語言&#xff0c;以其靈活性和跨平臺性征服了無數開發者。我們每天都在使用它&#xff0c;但它在后臺是如何工作的&#xff1f;一段看似簡單的JS代碼&#xff0c;在執行之前究竟經歷了哪些“變形記”&#xff1f;今天&#xff0c;讓我…

FPGA—硬件電路一旦上電配置完成,各個功能模塊會并行地持續工作

1.示例代碼參考這段代碼是用 Verilog 編寫的一個 LED 閃爍控制模塊&#xff0c;主要實現了 LED 按一定時間間隔循環移位閃爍的功能。下面詳細解釋其架構組成&#xff1a;模塊定義與端口聲明模塊名為 led_flash&#xff0c;包含三個端口&#xff1a;sys_clk&#xff1a;輸入端口…

從零到上線:Docker、Docker Compose 與 Runtime 安裝部署全指南(含實戰示例與應用場景)

文章目錄一、Docker 安裝1. Ubuntu / Debian&#xff08;官方倉庫&#xff09;2. RHEL / CentOS / Rocky / AlmaLinux3. 驗證4. macOS / Windows&#xff08;Docker Desktop&#xff09;二、Docker Compose&#xff08;V2&#xff09;安裝與基本用法1) 驗證2) 最小示例&#xf…

Java基礎篇02:基本語法

1 注釋 注釋是寫在程序中對代碼進行解釋說明的文字&#xff0c;方便自己和其他人查看&#xff0c;以便理解程序的。注釋分為三種&#xff1a;單行注釋、多行注釋、文檔注釋注釋不影響代碼的執行&#xff1a; 原因是編譯后的文件已經沒有注釋了// 這是單行注釋&#xff1a;。通常…

【SECS/GEM 】SECS/GEM 日志管理相關的消息

明白 ? 在 SECS/GEM 架構里&#xff0c;設備日志&#xff08;Equipment Logging 主要涉及 事件日志&#xff08;Event Log&#xff09;、報警日志&#xff08;Alarm Log&#xff09;、配方操作日志&#xff08;Recipe Log&#xff09;、以及用戶操作/命令日志。這些日志通過 S…

ragas 框架使用Chat-GLM模型報API 調用參數有誤,請檢查文檔

ragas 框架使用Chat-GLM模型報API 調用參數有誤&#xff0c;請檢查文檔解決方案 from ragas.llms import LangchainLLMWrapper # 點擊LangchainLLMWrapper 進入這個類找到這個方法直接 return 0.1出現問題原因 ChatGLM 不支持設置temperature等于0&#xff0c;默認的值太小了

Kaggle - LLM Science Exam 大模型做科學選擇題

Kaggle - LLM Science Exam Science Exam Simple Approach w/ Model Hub | Kaggle Platypus2-70B with Wikipedia RAG | Kaggle 5個選項只有一個選項正確&#xff0c;目標&#xff1a;回答一個選項序列&#xff08;只有前三個有效&#xff09; 輸出正確選項 &#xff08;可…

貪吃蛇魚小游戲抖音快手微信小程序看廣告流量主開源

核心優勢&#xff1a;為流量主運營者與新手量身打造 1. 為流量主運營者破解成本困局 本地化運行&#xff0c;零服務器成本&#xff1a;數據運行與存儲全程在用戶手機本地完成&#xff0c;無需部署服務器及后臺系統&#xff0c;徹底擺脫服務器租賃、維護等硬性支出&#xff0c;…

PDF Reader 編輯閱讀工具(Mac中文)

原文地址&#xff1a;PDF Reader 編輯閱讀 for Mac v5.2.0 PDF Reader Pro Mac&#xff0c;是一款PDF編輯閱讀&#xff0c;PDF Reader Pro讓您直接在 Mac 上進行PDF文件閱讀、筆記、編輯、轉換、創建PDF、簽署PDFs、填寫PDF Forms表單、設置密碼、合并拆分文件、水印等等&…

Django REST framework:SimpleRouter 使用指南

1. SimpleRouter 是什么&#xff1f; SimpleRouter 是 DRF&#xff08;Django REST framework&#xff09;提供的路由器&#xff0c;能根據 ViewSet 自動生成標準的 REST 路由&#xff0c;包括&#xff1a; GET /resources/ → 列表&#xff08;list&#xff09;POST /resource…

覆蓋Transformer、GAN:掩碼重建正在重塑時間序列領域!

隨著大數據與深度學習的發展&#xff0c;時間序列分析的建模能力顯著提升&#xff0c;而掩碼重建作為一種自監督學習范式&#xff0c;已成為提升序列表征能力的重要技術。該方法通過隨機掩碼部分數據并重建原始序列&#xff0c;迫使模型挖掘時序依賴性與潛在模式&#xff0c;在…

用AI做TikTok影視解說,全流程全自動成片,不懂外語也能做全球矩陣!

多語種解說&#xff1a; 短劇出海狂吸美金 多語種解說搶先機 TikTok、YouTube等平臺&#xff0c;尤其在非英語市場&#xff0c;內容供給仍遠遠不足&#xff0c;每一個小語種市場都是潛在藍海。 有人用英語講仙俠、西語講爽劇、日語講宮斗、阿語講懸疑&#xff0c;一夜漲粉百…

解密大語言模型推理:輸入處理背后的數學與工程實踐

解密大語言模型推理&#xff1a;輸入處理背后的數學與工程實踐當你向ChatGPT提問時&#xff0c;短短幾秒內就能獲得流暢的回答&#xff0c;這背后隱藏著怎樣的技術魔法&#xff1f;答案在于大語言模型高效推理過程中精妙的輸入處理機制。在現代大語言模型推理中&#xff0c;輸入…

02、連接服務器的幾種方式

02、連接服務器的幾種方式 1、Xshell 適用于Windows https://www.xshell.com/en/free-for-home-school/ 2、Termius 適用于MacOS 直接蘋果商店下載即可 3、IDEA 連接 Tools - Deployment - Browse Remote Host 1、打開Browse Remote Host2、添加服務3、輸入服務器連接信息并測試…

高并發系統設計方案(直播場景)

最近在準備面試&#xff0c;正把平時積累的筆記、項目中遇到的問題與解決方案、對核心原理的理解&#xff0c;以及高頻業務場景的應對策略系統梳理一遍&#xff0c;既能加深記憶&#xff0c;也能讓知識體系更扎實&#xff0c;供大家參考&#xff0c;歡迎討論。 1. 微服務拆分 …

網絡編程基礎:一文搞懂 Socket、HTTP、HTTPS、TCP/IP、SSL 的關系

在日常開發中&#xff0c;我們經常聽到 Socket、HTTP、HTTPS、TCP/IP、SSL 這些術語&#xff0c;這些概念往往容易混淆&#xff0c;且讓人感到困惑。本文將用最通俗易懂的方式來講清這些網絡概念及其相互關系。一、從寄信說起&#xff1a;網絡通信的本質假如你要給遠方的朋友寄…