Asp.Net Core IdentityServer4

Asp.Net Core IdentityServer4

(1)Authentication与Authorization

  • Authentication对访问者的用户身份进行验证,“用户是否登录成功”。
  • Authorization验证访问者的用户身份是否有对资源访问的访问权限,“用户是否有权限访问这个地址”。

(2)Identity框架

  • 采用基于角色的访问控制(Role-Based Access Control,简称RBAC)策略,内置了对用户、角色等表的管理及相关的接口,支持外部登录、2FA等
  • 标识框架使用EFCore对数据库进行操作,因此标识框架支持几乎所有数据库

(3)Identity框架使用

  • NuGet安装Microsoft.AspNetCore.Identity.EntityFrameworkCore等相关包
   <ItemGroup>
	<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="6.0.3" />	
	<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.3">
	  <PrivateAssets>all</PrivateAssets>
	  <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
	</PackageReference>
	<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.3" />	 
	<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.3">
	  <PrivateAssets>all</PrivateAssets>
	  <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
	</PackageReference>	 
	<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="6.0.1" /> 
    <PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
  </ItemGroup>

image-20220309234542213

  • 创建继承自IdentityDbContext的类
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;

public class IdDbContext : IdentityDbContext<User, Role, long>
{
	public IdDbContext(DbContextOptions<IdDbContext> options)
		: base(options)
	{
	}
	protected override void OnModelCreating(ModelBuilder modelBuilder)
	{
		base.OnModelCreating(modelBuilder);
		modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly);
	}
}
  • IdentityUser、IdentityRole,TKey代表主键的类型

Role

public class Role : IdentityRole<long>
{
}

User

public class User : IdentityUser<long>
{

}
  • Program注入Identity服务
//数据保护
builder.Services.AddDataProtection();

//Identity
builder.Services.AddIdentityCore<User>(options =>
{
    //指示密码是否必须包含数字
    options.Password.RequireDigit = false;
    //指示密码是否必须包含小写ASCII字符。  
    options.Password.RequireLowercase = false;
    //指示密码是否必须包含非字母数字字符。  
    options.Password.RequireNonAlphanumeric = false;
    //指示密码是否必须包含大写ASCII字符
    options.Password.RequireUppercase = false;
    //获取或设置密码必须的最小长度。 默认为6。  
    options.Password.RequiredLength = 6;
    //用于生成密码重置邮件中使用的令牌。  
    options.Tokens.PasswordResetTokenProvider = TokenOptions.DefaultEmailProvider;
    //获取或设置用于生成帐户确认中使用的令牌的令牌提供程序  
    options.Tokens.EmailConfirmationTokenProvider = TokenOptions.DefaultEmailProvider;
});

//注入RoleManager UserManager
var idBuilder = new IdentityBuilder(typeof(User), typeof(Role), builder.Services);
idBuilder.AddEntityFrameworkStores<IdDbContext>()
    .AddDefaultTokenProviders()
    .AddRoleManager<RoleManager<Role>>()
    .AddUserManager<UserManager<User>>();

image-20220309235224764

  • 创建IDesignTimeDbContextFactory用来迁移,sqlserver和mysql都可以,这里使用mysql
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;

class MyDesignTimeDbContextFactory : IDesignTimeDbContextFactory<IdDbContext>
{
    public IdDbContext CreateDbContext(string[] args)
    {
        DbContextOptionsBuilder<IdDbContext> builder = new();

        //环境变量获取方式
        //string connStr = Environment.GetEnvironmentVariable("ConnectionStrings:Default");

        //mysql
        string connStr = @"Server=localhost; Port=3306;Stmt=; Database=identitydb; Uid=root; Pwd=root;";
        var serverVersion = new MySqlServerVersion(new Version(5, 7, 28));
        builder.UseMySql(connStr, serverVersion);

        //sqlServer
        //string connStr = @"Data Source=.;Initial Catalog=YZKStudy;Persist Security Info=True;User ID=sa;Password=123456";
        //builder.UseSqlServer(connStr);


        //string connStr = "Data Source=.;Initial Catalog=Identitydb;Persist Security Info=True;User ID=sa;Password=123456";
        //builder.UseSqlServer(connStr);

        return new IdDbContext(builder.Options);
    }
}
  • 执行Add-Migration、Update-Database命令执行EF Core的数据库迁移。

image-20220309234903059

image-20220309234931338

  • 可以通过IdDbContext类来操作数据库,不过框架中提供了RoleManager、UserManager等类来简化对数据库的操作

LoginController

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;

namespace IdentityDemo.Controllers
{
	[Route("api/[controller]/[action]")]
	[ApiController]
	public class LoginController : ControllerBase
	{

		private readonly ILogger<LoginController> logger;
		private readonly RoleManager<Role> roleManager;
		private readonly UserManager<User> userManager;
		public LoginController(ILogger<LoginController> logger,
			RoleManager<Role> roleManager, UserManager<User> userManager)
		{
			this.logger = logger;
			this.roleManager = roleManager;
			this.userManager = userManager;
		}

		/// <summary>
		/// 登录
		/// </summary>
		/// <param name="req"></param>
		/// <returns></returns>
		[HttpPost]
		public async Task<ActionResult> Login(LoginRequest req)
		{
			string userName = req.UserName;
			string password = req.Password;
			var user = await userManager.FindByNameAsync(userName);
			if (user == null)
			{
				return NotFound($"用户名不存在{userName}");
			}
			if (await userManager.IsLockedOutAsync(user))
			{
				return BadRequest("LockedOut");
			}
			var success = await userManager.CheckPasswordAsync(user, password);		
			if (success)
			{
				return Ok("Success");
			}
			else
			{
				var r = await userManager.AccessFailedAsync(user);
				if (!r.Succeeded)
				{
					return BadRequest("AccessFailed failed");
				}
				return BadRequest("Failed");
			}
		}

		/// <summary>
		/// 发送验证码
		/// </summary>
		/// <param name="req"></param>
		/// <returns></returns>

		[HttpPost]
		public async Task<IActionResult> SendResetPasswordToken(
					SendResetPasswordTokenRequest req)
		{
			string email = req.Email;
			var user = await userManager.FindByEmailAsync(email);
			if (user == null)
			{
				return NotFound($"邮箱不存在{email}");
			}
			string token = await userManager.GeneratePasswordResetTokenAsync(user);
			logger.LogInformation($"向邮箱{user.Email}发送Token={token}");
			return Ok();
		}


		[HttpPost]
		public async Task<IActionResult> ResetPassword(ResetPasswordRequest req)
		{
			var user = await userManager.FindByNameAsync(req.UserName);
			var res = await userManager.ResetPasswordAsync(user, req.Token, req.Password);
			if (!res.Succeeded)
			{
				return BadRequest("重置失败");
			}
			else
			{
				return Ok("重置成功");
			}
		}

	}


	public record LoginRequest(string UserName, string Password);
	public record ResetPasswordRequest(string UserName, string Token, string Password);
	public record SendResetPasswordTokenRequest(string Email);
}

UserController

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;

namespace IdentityDemo.Controllers
{
    [Route("api/[controller]/[action]")]
    [ApiController]
    public class UserController : ControllerBase
    {
        private readonly ILogger<UserController> logger;
        private readonly RoleManager<Role> roleManager;
        private readonly UserManager<User> userManager;

        public UserController(ILogger<UserController> logger, RoleManager<Role> roleManager, UserManager<User> userManager)
        {
            this.logger = logger;
            this.roleManager = roleManager;
            this.userManager = userManager;
        }
        
        /// <summary>
        /// 创建peng用户 密码123456
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public async Task<ActionResult> CreateUserRole()
        {
            bool roleExists = await roleManager.RoleExistsAsync("admin");
            //如果不存在 创建admin角色
            if (!roleExists)
            {
                Role role = new Role { Name = "Admin" };
                var r = await roleManager.CreateAsync(role);
                if (!r.Succeeded)
                {
                    return BadRequest(r.Errors);
                }
            }
            //查找peng的用户
            User user = await this.userManager.FindByNameAsync("peng");
            //不存在就创建peng用户
            if (user == null)
            {
                user = new User { UserName = "peng", Email = "123@163.com", EmailConfirmed = true };
                //创建peng用户
                var r = await userManager.CreateAsync(user, "123456");
                if (!r.Succeeded)
                {
                    return BadRequest(r.Errors);
                }
                //peng分配admin角色
                r = await userManager.AddToRoleAsync(user, "admin");
                if (!r.Succeeded)
                {
                    return BadRequest(r.Errors);
                }
            }
            return Ok();
        }
     }
}

posted @   peng_boke  阅读(106)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
点击右上角即可分享
微信分享提示