Compare commits

...

8 Commits

26 changed files with 449 additions and 1075 deletions

View File

@ -5,34 +5,33 @@
ViewData["Title"] = "登录"; ViewData["Title"] = "登录";
} }
<h1>@ViewData["Title"]</h1> <h1 class="text-center">@ViewData["Title"]</h1>
<div class="row"> <div class="container">
<div class="col-md-4"> <div class="row justify-content-center">
<div class="col-md-6">
<section> <section>
<form id="account" method="post"> <form id="account" method="post" class="card p-4">
<h2>使用本地账户登录。</h2> <h2 class="text-center">使用本地账户登录。</h2>
<hr /> <hr />
<div asp-validation-summary="ModelOnly" class="text-danger" role="alert"></div> <div asp-validation-summary="ModelOnly" class="text-danger" role="alert"></div>
<div class="form-floating mb-3"> <div class="form-outline mb-4">
<input asp-for="Input.Email" class="form-control" autocomplete="username" aria-required="true" placeholder="name@example.com" /> <input asp-for="Input.Email" type="email" id="email" class="form-control" autocomplete="username" aria-required="true" placeholder="name@example.com" />
<label asp-for="Input.Email" class="form-label">电子邮件</label> <label asp-for="Input.Email" class="form-label">电子邮件</label>
<span asp-validation-for="Input.Email" class="text-danger"></span> <span asp-validation-for="Input.Email" class="text-danger"></span>
</div> </div>
<div class="form-floating mb-3"> <div class="form-outline mb-4">
<input asp-for="Input.Password" class="form-control" autocomplete="current-password" aria-required="true" placeholder="password" /> <input asp-for="Input.Password" type="password" id="password" class="form-control" autocomplete="current-password" aria-required="true" placeholder="password" />
<label asp-for="Input.Password" class="form-label">密码</label> <label asp-for="Input.Password" class="form-label">密码</label>
<span asp-validation-for="Input.Password" class="text-danger"></span> <span asp-validation-for="Input.Password" class="text-danger"></span>
</div> </div>
<div class="checkbox mb-3"> <div class="form-check mb-4">
<label asp-for="Input.RememberMe" class="form-label">
<input class="form-check-input" asp-for="Input.RememberMe" /> <input class="form-check-input" asp-for="Input.RememberMe" />
记住我 <label class="form-check-label" asp-for="Input.RememberMe">记住我</label>
</label>
</div> </div>
<div> <div class="d-grid gap-2">
<button id="login-submit" type="submit" class="w-100 btn btn-lg btn-primary">登录</button> <button id="login-submit" type="submit" class="btn btn-primary btn-block">登录</button>
</div> </div>
<div> <div class="text-center mt-3">
<p> <p>
<a id="forgot-password" asp-page="./ForgotPassword">忘记密码?</a> <a id="forgot-password" asp-page="./ForgotPassword">忘记密码?</a>
</p> </p>
@ -46,33 +45,33 @@
</form> </form>
</section> </section>
</div> </div>
<div class="col-md-6 col-md-offset-2"> </div>
</div>
<div class="row justify-content-end">
<div class="col-md-6">
<section> <section>
<h3>使用其他服务登录。</h3> <h3 class="text-center">使用其他服务登录。</h3>
<hr /> <hr />
@{ @if ((Model.ExternalLogins?.Count ?? 0) == 0)
if ((Model.ExternalLogins?.Count ?? 0) == 0)
{ {
<div> <div>
<p> <p class="text-center">
没有配置外部身份验证服务。请参阅<a href="https://go.microsoft.com/fwlink/?LinkID=532715">关于设置此ASP.NET应用程序以支持通过外部服务登录的文章</a>。 没有配置外部身份验证服务。请参阅<a href="https://go.microsoft.com/fwlink/?LinkID=532715">关于设置此ASP.NET应用程序以支持通过外部服务登录的文章</a>。
</p> </p>
</div> </div>
} }
else else
{ {
<form id="external-account" asp-page="./ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl" method="post" class="form-horizontal"> <form id="external-account" asp-page="./ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl" method="post" class="card p-4">
<div> <div class="d-grid gap-2">
<p>
@foreach (var provider in Model.ExternalLogins!) @foreach (var provider in Model.ExternalLogins!)
{ {
<button type="submit" class="btn btn-primary" name="provider" value="@provider.Name" title="Log in using your @provider.DisplayName account">@provider.DisplayName</button> <button type="submit" class="btn btn-primary" name="provider" value="@provider.Name" title="使用您的 @provider.DisplayName 账户登录">@provider.DisplayName</button>
} }
</p>
</div> </div>
</form> </form>
} }
}
</section> </section>
</div> </div>
</div> </div>

View File

@ -127,7 +127,8 @@ namespace AGSS.Areas.Identity.Pages.Account
_logger.LogInformation("User logged in."); _logger.LogInformation("User logged in.");
var user = await _userManager.FindByEmailAsync(Input.Email); var user = await _userManager.FindByEmailAsync(Input.Email);
var token = _jwt.GenerateJwtToken(user); var roles = await _userManager.GetRolesAsync(user);
var token = _jwt.GenerateJwtToken(user,roles);
var frontendCallback = $"{Request.Query["frontendCallback"]}?token={token}"; var frontendCallback = $"{Request.Query["frontendCallback"]}?token={token}";

View File

@ -49,5 +49,8 @@
</div> </div>
@section Scripts { @section Scripts {
<partial name="_ValidationScriptsPartial" /> @await Html.PartialAsync("_ValidationScriptsPartial")
<script type="text/javascript" src="~/lib/qrcode/qrcode.js"></script>
<script type="text/javascript" src="~/js/qr.js"></script>
} }

View File

@ -18,15 +18,20 @@
<span asp-validation-for="Input.Email" class="text-danger"></span> <span asp-validation-for="Input.Email" class="text-danger"></span>
</div> </div>
<div class="form-floating mb-3"> <div class="form-floating mb-3">
<input asp-for="Input.Password" class="form-control" autocomplete="new-password" aria-required="true" placeholder="password" /> <input asp-for="Input.Password" class="form-control" autocomplete="new-password" aria-required="true" placeholder="请输入密码" />
<label asp-for="Input.Password">密码</label> <label asp-for="Input.Password">密码</label>
<span asp-validation-for="Input.Password" class="text-danger"></span> <span asp-validation-for="Input.Password" class="text-danger"></span>
</div> </div>
<div class="form-floating mb-3"> <div class="form-floating mb-3">
<input asp-for="Input.ConfirmPassword" class="form-control" autocomplete="new-password" aria-required="true" placeholder="password" /> <input asp-for="Input.ConfirmPassword" class="form-control" autocomplete="new-sex" aria-required="true" placeholder="确认密码" />
<label asp-for="Input.ConfirmPassword">确认密码</label> <label asp-for="Input.ConfirmPassword">确认密码</label>
<span asp-validation-for="Input.ConfirmPassword" class="text-danger"></span> <span asp-validation-for="Input.ConfirmPassword" class="text-danger"></span>
</div> </div>
<div class="form-floating mb-3">
<input asp-for="Input.Sex" class="form-control" autocomplete="username" aria-required="true" placeholder="男/女" />
<label asp-for="Input.Sex">性别</label>
<span asp-validation-for="Input.Sex" class="text-danger"></span>
</div>
<button id="registerSubmit" type="submit" class="w-100 btn btn-lg btn-primary">注册</button> <button id="registerSubmit" type="submit" class="w-100 btn btn-lg btn-primary">注册</button>
</form> </form>
</div> </div>

View File

@ -104,6 +104,12 @@ namespace AGSS.Areas.Identity.Pages.Account
[Display(Name = "Confirm password")] [Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; } public string ConfirmPassword { get; set; }
[MaxLength(10)]
[Display(Name = "Confirm password")]
public string Sex { get; set; }
} }
@ -120,7 +126,8 @@ namespace AGSS.Areas.Identity.Pages.Account
if (ModelState.IsValid) if (ModelState.IsValid)
{ {
var user = CreateUser(); var user = CreateUser();
user.Id = Guid.NewGuid().ToString();
user.Sex = Input.Sex;
await _userStore.SetUserNameAsync(user, Input.Email, CancellationToken.None); await _userStore.SetUserNameAsync(user, Input.Email, CancellationToken.None);
await _emailStore.SetEmailAsync(user, Input.Email, CancellationToken.None); await _emailStore.SetEmailAsync(user, Input.Email, CancellationToken.None);
var result = await _userManager.CreateAsync(user, Input.Password); var result = await _userManager.CreateAsync(user, Input.Password);
@ -128,8 +135,8 @@ namespace AGSS.Areas.Identity.Pages.Account
if (result.Succeeded) if (result.Succeeded)
{ {
_logger.LogInformation("User created a new account with password."); _logger.LogInformation("User created a new account with password.");
var user1 = await _userManager.FindByEmailAsync(Input.Email); var roles = await _userManager.GetRolesAsync(user);
var token = _jwt.GenerateJwtToken(user1); var token = _jwt.GenerateJwtToken(user,roles);
var frontendCallback = $"{Request.Query["frontendCallback"]}?token={token}"; var frontendCallback = $"{Request.Query["frontendCallback"]}?token={token}";

View File

@ -0,0 +1,240 @@
using AGSS.Models.DTOs;
using AGSS.Models.Entities;
using AGSS.Models.Template;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
namespace AGSS.Controllers.Admin;
/// <summary>
/// 控制器类,用于管理角色相关的操作,包括添加角色、分配角色给用户以及通过角色查询用户。
/// 该控制器仅限具有"Admin"角色的用户访问。
/// </summary>
[Authorize(Roles = "Admin")]
[Route("api/v1/[controller]/[action]")]
public class AdminRoleControllers:ControllerBase
{
/// <summary>
/// 角色管理器,用于处理角色相关的操作,如创建、查询等。
/// 此角色管理器实例主要用于与RoleModel类型的实体进行交互
/// 支持添加新角色、为用户分配角色等功能。
/// </summary>
private readonly RoleManager<RoleModel> _roleManager;
/// <summary>
/// 用户管理器实例,用于处理用户相关的操作如添加角色、查询用户等。
/// 此实例通过依赖注入的方式在构造函数中初始化,并在整个控制器生命周期内可用。
/// </summary>
private readonly UserManager<UserModel> _userManager; // Assuming UserModel is the type of user
/// <summary>
/// 管理员角色控制器,用于处理与角色相关的操作,如添加角色、分配角色给用户以及通过角色查询用户。
/// 该控制器下的所有方法都需要管理员权限才能访问。
/// </summary>
public AdminRoleControllers(RoleManager<RoleModel> roleManager, UserManager<UserModel> userManager)
{
_roleManager = roleManager;
_userManager = userManager;
}
/// <summary>
/// 添加新角色
/// </summary>
/// <param name="role">要添加的角色信息</param>
/// <returns>返回操作结果,包含状态码、消息和数据</returns>
[HttpPost]
public async Task<IActionResult> AddRole([FromBody] RoleModel role)
{
if (role == null || string.IsNullOrWhiteSpace(role.Name))
{
return Ok(new ReturnTemplate(400,"创建失败,请提供名字",""));
}
var result = await _roleManager.CreateAsync(role);
if (result.Succeeded)
{
return Ok(new ReturnTemplate(200,"创建成功",role));
}
else
{
return Ok(new ReturnTemplate(StatusCodes.Status500InternalServerError,"创建失败","Failed to create role: " + string.Join(", ", result.Errors.Select(e => e.Description))));
}
}
/// <summary>
/// 为指定用户分配角色
/// </summary>
/// <param name="userId">用户的唯一标识符</param>
/// <param name="roleName">要分配的角色名称</param>
/// <returns>返回一个包含操作结果的ReturnTemplate对象其中Code表示状态码Msg表示消息Data表示附加数据如果有的话</returns>
[HttpPost]
public async Task<IActionResult> EndowRole(string userId, string roleName)
{
var user = await _userManager.FindByIdAsync(userId);
if (user == null)
{
return Ok(new ReturnTemplate(400, "用户不存在", ""));
}
var role = await _roleManager.FindByNameAsync(roleName);
if (role == null)
{
return Ok(new ReturnTemplate(400, "角色不存在", ""));
}
var result = await _userManager.AddToRoleAsync(user, role.Name);
if (result.Succeeded)
{
return Ok(new ReturnTemplate(200, "角色分配成功", user));
}
else
{
return Ok(new ReturnTemplate(StatusCodes.Status500InternalServerError, "角色分配失败", "Failed to endow role: " + string.Join(", ", result.Errors.Select(e => e.Description))));
}
}
/// <summary>
/// 删除指定用户。
/// </summary>
/// <param name="userId">要删除的用户的唯一标识符。</param>
/// <returns>返回操作结果包含状态码、消息和数据。如果删除成功则返回200状态码如果用户ID为空或未找到指定用户则分别返回400或404状态码若删除过程中出现错误则返回500状态码并附带错误信息。</returns>
[HttpPost]
public async Task<IActionResult> DelUser(string userId)
{
if (string.IsNullOrWhiteSpace(userId))
{
return Ok(new ReturnTemplate(400, "你填写的用户ID是空的~", null));
}
var user = await _userManager.FindByIdAsync(userId);
if (user == null)
{
return Ok(new ReturnTemplate(404, "未找到指定用户哦·~", null));
}
// 删除用户
var result = await _userManager.DeleteAsync(user);
if (result.Succeeded)
{
return Ok(new ReturnTemplate(200, "用户删除成功,不要留念这个用户哦~", null));
}
else
{
return StatusCode(500, new ReturnTemplate(500, "发生了一些不可预料的错误555", result.Errors));
}
}
[HttpPost]
public async Task<IActionResult> SetMenu([FromBody]MenuRequest request)
{
if (string.IsNullOrWhiteSpace(request.Id) || string.IsNullOrWhiteSpace(request.MenuName))
{
return Ok(new ReturnTemplate(400, "请求参数无效(有的参数是空的哦~", ""));
}
var user=await _userManager.FindByIdAsync(request.Id);
if (user==null)
{
return Ok(new ReturnTemplate(404, "Sorry你输入的用户我们找不到", ""));
}
user.MenuCode = request.MenuCode;
user.MenuName = request.MenuName;
var result= await _userManager.UpdateAsync(user);
if (result.Succeeded)
{
return Ok(new ReturnTemplate(200, "配置成功啦!", ""));
}
else
{
return StatusCode(500, new ReturnTemplate(500, "删除用户时发生错误", result.Errors));
}
}
/// <summary>
/// 通过角色查询用户,支持分页
/// </summary>
/// <param name="request">包含角色名称、页码和每页大小的请求对象</param>
/// <returns>返回包含总用户数和当前页用户的响应对象</returns>
[HttpPost]
public async Task<IActionResult> SearchUserFromRole([FromBody] SearchUserFromRoleRequest request)
{
if (string.IsNullOrWhiteSpace(request.RoleName))
{
return Ok(new ReturnTemplate(400, "角色名称不能为空", null));
}
var role = await _roleManager.FindByNameAsync(request.RoleName);
if (role == null)
{
return Ok(new ReturnTemplate(400, "角色不存在", null));
}
var usersInRole = await _userManager.GetUsersInRoleAsync(role.Name);
var totalUsers = usersInRole.Count;
var pagedUsers = usersInRole
.Skip((request.Page - 1) * request.PageSize)
.Take(request.PageSize)
.ToList();
var response = new SearchUserFromRoleResponse
{
TotalCount = totalUsers,
Users = pagedUsers
};
return Ok(new ReturnTemplate(200, "查询成功", response));
}
/// <summary>
/// 用于通过角色名称查询用户列表的请求模型。支持分页功能。
/// </summary>
public class SearchUserFromRoleRequest
{
/// <summary>
/// 表示角色的名称。此属性用于指定或获取与用户管理相关的角色名称。
/// 在进行角色分配、查询等操作时,需要提供正确的角色名称以确保操作的成功执行。
/// </summary>
public string RoleName { get; set; }
/// <summary>
/// 表示当前请求的页码默认为1。用于分页查询用户时指定从哪一页开始获取数据。
/// </summary>
public int Page { get; set; } = 1;
/// <summary>
/// 每页显示的用户数量。默认值为10。
/// 该属性用于分页查询中指定每一页应包含的用户条目数。
/// </summary>
public int PageSize { get; set; } = 10;
}
/// <summary>
/// 表示通过角色查询用户后返回的响应数据。
/// 该类用于封装查询结果,包括总用户数和分页后的用户列表。
/// </summary>
public class SearchUserFromRoleResponse
{
/// <summary>
/// 表示属于特定角色的用户总数。
/// </summary>
/// <remarks>此属性用于分页查询中,返回匹配给定角色名称的所有用户的数量。</remarks>
public int TotalCount { get; set; }
/// <summary>
/// 表示属于特定角色的用户列表。该属性用于存储和返回在给定角色下的所有用户。
/// </summary>
/// <remarks>此列表通常作为查询结果的一部分,例如通过角色名搜索用户时返回的数据。</remarks>
public List<UserModel> Users { get; set; }
}
}

View File

@ -1,3 +1,4 @@
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims; using System.Security.Claims;
using AGSS.Models.Entities; using AGSS.Models.Entities;
using AGSS.Models.Template; using AGSS.Models.Template;
@ -7,25 +8,38 @@ using Microsoft.AspNetCore.Mvc;
namespace AGSS.Controllers.User; namespace AGSS.Controllers.User;
/// <summary>
/// 用户控制器提供与用户相关的API接口。
/// </summary>
/// <remarks>此控制器需要授权才能访问其方法。</remarks>
[Authorize] [Authorize]
[Route("api/v1/[controller]")] [Route("api/v1/[controller]/[action]")]
public class UserControllers:ControllerBase public class UserControllers:ControllerBase
{ {
/// <summary>
/// 用户服务实例,用于执行与用户相关的操作。
/// 该服务提供了一系列方法来处理用户的查询和更新等操作,
/// 包括但不限于获取用户详细信息、修改用户资料等功能。
/// </summary>
private readonly UserService _userService; private readonly UserService _userService;
/// <summary>
/// 用户控制器提供用户相关操作的API接口。
/// </summary>
public UserControllers(UserService userService, UserManager<UserModel> userManager) public UserControllers(UserService userService, UserManager<UserModel> userManager)
{ {
_userService = userService; _userService = userService;
} }
/// <summary>
/// 获取当前登录用户的个人信息。
/// </summary>
/// <returns>返回一个包含状态码、消息和用户信息的ReturnTemplate对象。如果成功状态码为200如果失败状态码为500。</returns>
[HttpGet] [HttpGet]
public async Task<IActionResult> My() public async Task<IActionResult> My()
{ {
string userId = this.User.FindFirst(ClaimTypes.NameIdentifier)!.Value; string userId = this.User.FindFirst(JwtRegisteredClaimNames.Sub)!.Value;
if (string.IsNullOrEmpty(userId)) if (string.IsNullOrEmpty(userId))
{ {
return Ok(new ReturnTemplate(500,"获取用户失败JWT解析错误",null)); return Ok(new ReturnTemplate(500,"获取用户失败JWT解析错误",null));

View File

@ -4,11 +4,26 @@ using Microsoft.EntityFrameworkCore;
namespace AGSS.DbSet namespace AGSS.DbSet
{ {
public class ApplicationDbContext : IdentityDbContext<UserModel> public class ApplicationDbContext : IdentityDbContext<UserModel,RoleModel,string>
{ {
public override DbSet<UserModel> Users { get; set; }
public override DbSet<RoleModel> Roles { get; set; }
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options) : base(options)
{ {
} }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// 在这里添加额外的配置,如果需要的话
// 例如:
// modelBuilder.Entity<UserModel>().ToTable("CustomUsers");
// modelBuilder.Entity<RoleModel>().ToTable("CustomRoles");
}
} }
} }

View File

@ -1,53 +0,0 @@
// <auto-generated />
using System;
using AGSS.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace AGSS.Migrations
{
[DbContext(typeof(DBContext))]
[Migration("20250702100149_Initial")]
partial class Initial
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "9.0.6")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("AGSS.Models.Entities.UserModel", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("AuthId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Password")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("UserModels");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -1,36 +0,0 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace AGSS.Migrations
{
/// <inheritdoc />
public partial class Initial : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "UserModels",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
AuthId = table.Column<string>(type: "text", nullable: false),
Email = table.Column<string>(type: "text", nullable: false),
Password = table.Column<string>(type: "text", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_UserModels", x => x.Id);
});
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "UserModels");
}
}
}

View File

@ -1,45 +0,0 @@
// <auto-generated />
using System;
using AGSS.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace AGSS.Migrations
{
[DbContext(typeof(DBContext))]
[Migration("20250702110815_usernew")]
partial class usernew
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "9.0.6")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("AGSS.Models.Entities.UserModel", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("AuthId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("UserModels");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -1,40 +0,0 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace AGSS.Migrations
{
/// <inheritdoc />
public partial class usernew : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Email",
table: "UserModels");
migrationBuilder.DropColumn(
name: "Password",
table: "UserModels");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "Email",
table: "UserModels",
type: "text",
nullable: false,
defaultValue: "");
migrationBuilder.AddColumn<string>(
name: "Password",
table: "UserModels",
type: "text",
nullable: false,
defaultValue: "");
}
}
}

View File

@ -1,70 +0,0 @@
// <auto-generated />
using System;
using AGSS.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace AGSS.Migrations
{
[DbContext(typeof(DBContext))]
[Migration("20250705081221_newuser")]
partial class newuser
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "9.0.6")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("AGSS.Models.Entities.UserModel", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("AuthId")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.Property<string>("Birthday")
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.Property<string>("Config")
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<string>("Description")
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<string>("JobCode")
.HasMaxLength(10)
.HasColumnType("character varying(10)");
b.Property<string>("JobName")
.HasMaxLength(10)
.HasColumnType("character varying(10)");
b.Property<string>("Sex")
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.HasKey("Id");
b.ToTable("UserModels");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -1,102 +0,0 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace AGSS.Migrations
{
/// <inheritdoc />
public partial class newuser : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "AuthId",
table: "UserModels",
type: "character varying(50)",
maxLength: 50,
nullable: false,
oldClrType: typeof(string),
oldType: "text");
migrationBuilder.AddColumn<string>(
name: "Birthday",
table: "UserModels",
type: "character varying(20)",
maxLength: 20,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "Config",
table: "UserModels",
type: "character varying(200)",
maxLength: 200,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "Description",
table: "UserModels",
type: "character varying(100)",
maxLength: 100,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "JobCode",
table: "UserModels",
type: "character varying(10)",
maxLength: 10,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "JobName",
table: "UserModels",
type: "character varying(10)",
maxLength: 10,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "Sex",
table: "UserModels",
type: "character varying(20)",
maxLength: 20,
nullable: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Birthday",
table: "UserModels");
migrationBuilder.DropColumn(
name: "Config",
table: "UserModels");
migrationBuilder.DropColumn(
name: "Description",
table: "UserModels");
migrationBuilder.DropColumn(
name: "JobCode",
table: "UserModels");
migrationBuilder.DropColumn(
name: "JobName",
table: "UserModels");
migrationBuilder.DropColumn(
name: "Sex",
table: "UserModels");
migrationBuilder.AlterColumn<string>(
name: "AuthId",
table: "UserModels",
type: "text",
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(50)",
oldMaxLength: 50);
}
}
}

View File

@ -1,300 +0,0 @@
// <auto-generated />
using System;
using AGSS.DbSet;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace AGSS.Migrations
{
[DbContext(typeof(ApplicationDbContext))]
[Migration("20250708111442_user")]
partial class user
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "9.0.6")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("AGSS.Models.Entities.UserModel", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<int>("AccessFailedCount")
.HasColumnType("integer");
b.Property<string>("Birthday")
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text");
b.Property<string>("Config")
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<string>("Description")
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<bool>("EmailConfirmed")
.HasColumnType("boolean");
b.Property<string>("JobCode")
.HasMaxLength(10)
.HasColumnType("character varying(10)");
b.Property<string>("JobName")
.HasMaxLength(10)
.HasColumnType("character varying(10)");
b.Property<bool>("LockoutEnabled")
.HasColumnType("boolean");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("timestamp with time zone");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("PasswordHash")
.HasColumnType("text");
b.Property<string>("PhoneNumber")
.HasColumnType("text");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("boolean");
b.Property<string>("SecurityStamp")
.HasColumnType("text");
b.Property<string>("Sex")
.HasColumnType("text");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("boolean");
b.Property<string>("UserName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex");
b.ToTable("AspNetUsers", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("AspNetRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("text");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<string>("RoleId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("text");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider")
.HasColumnType("text");
b.Property<string>("ProviderKey")
.HasColumnType("text");
b.Property<string>("ProviderDisplayName")
.HasColumnType("text");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("text");
b.Property<string>("RoleId")
.HasColumnType("text");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("text");
b.Property<string>("LoginProvider")
.HasColumnType("text");
b.Property<string>("Name")
.HasColumnType("text");
b.Property<string>("Value")
.HasColumnType("text");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("AGSS.Models.Entities.UserModel", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("AGSS.Models.Entities.UserModel", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("AGSS.Models.Entities.UserModel", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("AGSS.Models.Entities.UserModel", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
#pragma warning restore 612, 618
}
}
}

View File

@ -1,229 +0,0 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace AGSS.Migrations
{
/// <inheritdoc />
public partial class user : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "AspNetRoles",
columns: table => new
{
Id = table.Column<string>(type: "text", nullable: false),
Name = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
NormalizedName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
ConcurrencyStamp = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetRoles", x => x.Id);
});
migrationBuilder.CreateTable(
name: "AspNetUsers",
columns: table => new
{
Id = table.Column<string>(type: "text", nullable: false),
Sex = table.Column<string>(type: "text", nullable: true),
Description = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: true),
Config = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: true),
JobCode = table.Column<string>(type: "character varying(10)", maxLength: 10, nullable: true),
JobName = table.Column<string>(type: "character varying(10)", maxLength: 10, nullable: true),
Birthday = table.Column<string>(type: "character varying(20)", maxLength: 20, nullable: true),
UserName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
NormalizedUserName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
Email = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
NormalizedEmail = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
EmailConfirmed = table.Column<bool>(type: "boolean", nullable: false),
PasswordHash = table.Column<string>(type: "text", nullable: true),
SecurityStamp = table.Column<string>(type: "text", nullable: true),
ConcurrencyStamp = table.Column<string>(type: "text", nullable: true),
PhoneNumber = table.Column<string>(type: "text", nullable: true),
PhoneNumberConfirmed = table.Column<bool>(type: "boolean", nullable: false),
TwoFactorEnabled = table.Column<bool>(type: "boolean", nullable: false),
LockoutEnd = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
LockoutEnabled = table.Column<bool>(type: "boolean", nullable: false),
AccessFailedCount = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUsers", x => x.Id);
});
migrationBuilder.CreateTable(
name: "AspNetRoleClaims",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
RoleId = table.Column<string>(type: "text", nullable: false),
ClaimType = table.Column<string>(type: "text", nullable: true),
ClaimValue = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id);
table.ForeignKey(
name: "FK_AspNetRoleClaims_AspNetRoles_RoleId",
column: x => x.RoleId,
principalTable: "AspNetRoles",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserClaims",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
UserId = table.Column<string>(type: "text", nullable: false),
ClaimType = table.Column<string>(type: "text", nullable: true),
ClaimValue = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserClaims", x => x.Id);
table.ForeignKey(
name: "FK_AspNetUserClaims_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserLogins",
columns: table => new
{
LoginProvider = table.Column<string>(type: "text", nullable: false),
ProviderKey = table.Column<string>(type: "text", nullable: false),
ProviderDisplayName = table.Column<string>(type: "text", nullable: true),
UserId = table.Column<string>(type: "text", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey });
table.ForeignKey(
name: "FK_AspNetUserLogins_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserRoles",
columns: table => new
{
UserId = table.Column<string>(type: "text", nullable: false),
RoleId = table.Column<string>(type: "text", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId });
table.ForeignKey(
name: "FK_AspNetUserRoles_AspNetRoles_RoleId",
column: x => x.RoleId,
principalTable: "AspNetRoles",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_AspNetUserRoles_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserTokens",
columns: table => new
{
UserId = table.Column<string>(type: "text", nullable: false),
LoginProvider = table.Column<string>(type: "text", nullable: false),
Name = table.Column<string>(type: "text", nullable: false),
Value = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name });
table.ForeignKey(
name: "FK_AspNetUserTokens_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_AspNetRoleClaims_RoleId",
table: "AspNetRoleClaims",
column: "RoleId");
migrationBuilder.CreateIndex(
name: "RoleNameIndex",
table: "AspNetRoles",
column: "NormalizedName",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_AspNetUserClaims_UserId",
table: "AspNetUserClaims",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_AspNetUserLogins_UserId",
table: "AspNetUserLogins",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_AspNetUserRoles_RoleId",
table: "AspNetUserRoles",
column: "RoleId");
migrationBuilder.CreateIndex(
name: "EmailIndex",
table: "AspNetUsers",
column: "NormalizedEmail");
migrationBuilder.CreateIndex(
name: "UserNameIndex",
table: "AspNetUsers",
column: "NormalizedUserName",
unique: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "AspNetRoleClaims");
migrationBuilder.DropTable(
name: "AspNetUserClaims");
migrationBuilder.DropTable(
name: "AspNetUserLogins");
migrationBuilder.DropTable(
name: "AspNetUserRoles");
migrationBuilder.DropTable(
name: "AspNetUserTokens");
migrationBuilder.DropTable(
name: "AspNetRoles");
migrationBuilder.DropTable(
name: "AspNetUsers");
}
}
}

View File

@ -22,6 +22,32 @@ namespace AGSS.Migrations
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("AGSS.Models.Entities.RoleModel", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("AspNetRoles", (string)null);
});
modelBuilder.Entity("AGSS.Models.Entities.UserModel", b => modelBuilder.Entity("AGSS.Models.Entities.UserModel", b =>
{ {
b.Property<string>("Id") b.Property<string>("Id")
@ -67,6 +93,14 @@ namespace AGSS.Migrations
b.Property<DateTimeOffset?>("LockoutEnd") b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("timestamp with time zone"); .HasColumnType("timestamp with time zone");
b.Property<string>("MenuCode")
.HasMaxLength(500)
.HasColumnType("character varying(500)");
b.Property<string>("MenuName")
.HasMaxLength(500)
.HasColumnType("character varying(500)");
b.Property<string>("NormalizedEmail") b.Property<string>("NormalizedEmail")
.HasMaxLength(256) .HasMaxLength(256)
.HasColumnType("character varying(256)"); .HasColumnType("character varying(256)");
@ -109,32 +143,6 @@ namespace AGSS.Migrations
b.ToTable("AspNetUsers", (string)null); b.ToTable("AspNetUsers", (string)null);
}); });
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("AspNetRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b => modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{ {
b.Property<int>("Id") b.Property<int>("Id")
@ -243,7 +251,7 @@ namespace AGSS.Migrations
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b => modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{ {
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) b.HasOne("AGSS.Models.Entities.RoleModel", null)
.WithMany() .WithMany()
.HasForeignKey("RoleId") .HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade) .OnDelete(DeleteBehavior.Cascade)
@ -270,7 +278,7 @@ namespace AGSS.Migrations
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b => modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{ {
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) b.HasOne("AGSS.Models.Entities.RoleModel", null)
.WithMany() .WithMany()
.HasForeignKey("RoleId") .HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade) .OnDelete(DeleteBehavior.Cascade)

View File

@ -1,67 +0,0 @@
// <auto-generated />
using System;
using AGSS.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace AGSS.Migrations
{
[DbContext(typeof(DBContext))]
partial class DBContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "9.0.6")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("AGSS.Models.Entities.UserModel", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("AuthId")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.Property<string>("Birthday")
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.Property<string>("Config")
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<string>("Description")
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<string>("JobCode")
.HasMaxLength(10)
.HasColumnType("character varying(10)");
b.Property<string>("JobName")
.HasMaxLength(10)
.HasColumnType("character varying(10)");
b.Property<string>("Sex")
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.HasKey("Id");
b.ToTable("UserModels");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,8 @@
namespace AGSS.Models.DTOs;
public struct MenuRequest
{
public string Id { get; set; }
public string MenuName { get; set; }
public string? MenuCode { get; set; }
}

View File

@ -3,7 +3,7 @@ using Microsoft.AspNetCore.Identity;
namespace AGSS.Models.Entities; namespace AGSS.Models.Entities;
public class UserModel:IdentityUser public class UserModel:IdentityUser<string>
{ {
public string? Sex { get; set; } public string? Sex { get; set; }
@ -17,5 +17,14 @@ public class UserModel:IdentityUser
public string? JobName { get; set; } public string? JobName { get; set; }
[MaxLength(20)] [MaxLength(20)]
public string? Birthday { get; set; } public string? Birthday { get; set; }
[MaxLength(500)]
public string? MenuCode { get; set; }
[MaxLength(500)]
public string? MenuName { get; set; }
}
public class RoleModel : IdentityRole<string>
{
} }

View File

@ -33,7 +33,7 @@ builder.Services.AddDbContext<ApplicationDbContext>(opt =>
opt.UseNpgsql(builder.Configuration.GetConnectionString("DBContext"))); opt.UseNpgsql(builder.Configuration.GetConnectionString("DBContext")));
// Identity 配置 // Identity 配置
builder.Services.AddIdentity<UserModel, IdentityRole>() builder.Services.AddIdentity<UserModel, RoleModel>()
.AddEntityFrameworkStores<ApplicationDbContext>() .AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders() .AddDefaultTokenProviders()
.AddDefaultUI(); .AddDefaultUI();

View File

@ -15,28 +15,30 @@ public class Jwt
_configuration = configuration; _configuration = configuration;
} }
public string BuildToken(IEnumerable<Claim> claims)
public string GenerateJwtToken(UserModel user)
{ {
var claims = new[] DateTime expires = DateTime.Now.AddDays(int.Parse(_configuration["Jwt:ExpireMinutes"]));
byte[] keyBytes = Encoding.UTF8.GetBytes(_configuration["Jwt:Key"]);
var secKey = new SymmetricSecurityKey(keyBytes);
var credentials = new SigningCredentials(secKey,
SecurityAlgorithms.HmacSha256Signature);
var tokenDescriptor = new JwtSecurityToken(expires: expires,
signingCredentials: credentials, claims: claims);
return new JwtSecurityTokenHandler().WriteToken(tokenDescriptor);
}
public string GenerateJwtToken(UserModel user,IList<string> roles)
{ {
new Claim(JwtRegisteredClaimNames.Sub, user.Email), var claims = new List<Claim>();
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()), claims.Add(new Claim(JwtRegisteredClaimNames.Sub, user.Id.ToString()));
new Claim(ClaimTypes.NameIdentifier, user.Id) claims.Add(new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()));
}; // var roles = await user.GetRolesAsync(user);
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes( foreach (string role in roles)
_configuration["Jwt:Key"])); {
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); claims.Add(new Claim(ClaimTypes.Role, role));
var expires = DateTime.Now.AddMinutes( }
Convert.ToDouble(_configuration["Jwt:ExpireMinutes"])); string jwtToken = BuildToken(claims);
var token = new JwtSecurityToken( return jwtToken;
issuer: _configuration["Jwt:Issuer"],
audience: _configuration["Jwt:Audience"],
claims: claims,
expires: expires,
signingCredentials: creds
);
return new JwtSecurityTokenHandler().WriteToken(token);
} }
} }

View File

@ -15,6 +15,7 @@
}, },
"AllowedHosts": "*", "AllowedHosts": "*",
"Jwt": { "Jwt": {
"ExpireMinutes": "4",
"Issuer": "https://api.zeronode.cn/api", "Issuer": "https://api.zeronode.cn/api",
"Audience": "https://api.zeronode.cn/api", "Audience": "https://api.zeronode.cn/api",
"Key": "7wU9bdVfBsX3jITh0w4bgE6fkvLk8pIcZRSUw6r8HQUnXfslYxlx4c4E0ZAIw4Ak" "Key": "7wU9bdVfBsX3jITh0w4bgE6fkvLk8pIcZRSUw6r8HQUnXfslYxlx4c4E0ZAIw4Ak"

View File

@ -15,6 +15,7 @@
}, },
"AllowedHosts": "*", "AllowedHosts": "*",
"Jwt": { "Jwt": {
"ExpireMinutes": "4",
"Issuer": "https://api.zeronode.cn/api", "Issuer": "https://api.zeronode.cn/api",
"Audience": "https://api.zeronode.cn/api", "Audience": "https://api.zeronode.cn/api",
"Key": "7wU9bdVfBsX3jITh0w4bgE6fkvLk8pIcZRSUw6r8HQUnXfslYxlx4c4E0ZAIw4Ak" "Key": "7wU9bdVfBsX3jITh0w4bgE6fkvLk8pIcZRSUw6r8HQUnXfslYxlx4c4E0ZAIw4Ak"

View File

@ -0,0 +1 @@
<input asp-for="Input.Email" type="email" class="form-control validate form-outline" autocomplete="username" aria-required="true" placeholder="name@example.com" />

View File

@ -21,6 +21,8 @@ CREATE TABLE "AspNetUsers" (
"JobCode" character varying(10), "JobCode" character varying(10),
"JobName" character varying(10), "JobName" character varying(10),
"Birthday" character varying(20), "Birthday" character varying(20),
"MenuCode" character varying(500),
"MenuName" character varying(500),
"UserName" character varying(256), "UserName" character varying(256),
"NormalizedUserName" character varying(256), "NormalizedUserName" character varying(256),
"Email" character varying(256), "Email" character varying(256),
@ -97,7 +99,7 @@ CREATE INDEX "EmailIndex" ON "AspNetUsers" ("NormalizedEmail");
CREATE UNIQUE INDEX "UserNameIndex" ON "AspNetUsers" ("NormalizedUserName"); CREATE UNIQUE INDEX "UserNameIndex" ON "AspNetUsers" ("NormalizedUserName");
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
VALUES ('20250708111442_user', '9.0.6'); VALUES ('20250709144855_Initial', '9.0.6');
COMMIT; COMMIT;