Asp.net core Identity

发布时间 2023-07-20 12:12:13作者: shanawdj

身份验证是确定用户身份的过程。 授权是确定用户是否有权访问资源的过程。

基本上正式项目都有用户中心模块,都需要实现身份验证和授权功能。Asp.net core中,微软官方给我们提供了Identity帮助我们实现这些功能。

如何使用Identity,下文将给出示例:

数据库

基本的配置就不再讲了,都是一样的,但是在自定义context这里:

public class MyContext : IdentityDbContext
{
    
}

不继承DbContext,而是继承IdentityDbContext(其实f12进去会发现IdentityDbContext是集成了DbContext的)。

依赖注入:

///efcore mysql
builder.Services.AddDbContext<MyContext>(opt =>
{
    opt.UseMySql(builder.Configuration.GetConnectionString("Default"),                        MySqlServerVersion.LatestSupportedServerVersion);
});

//Identity
builder.Services.AddIdentity<IdentityUser, IdentityRole>().AddEntityFrameworkStores<MyContext>();

然后迁移,数据库里会多出几张表:

image-20230720105846205

表中的字段都是预定义的,我们开发的时候经常会需要自定义一些字段,完全没有问题。IdentityDbContext支持泛型,创建一个user类继承IdentityUser,然后让MyContext继承泛型的IdentityDbContext就行了。

添加用户

Identity中提供了很多领域服务类,如UserManager,RoleManager,SignInManager,我们直接通过依赖注入就能使用,调用现成的方法来实现绝大部分功能。

[ApiController]
[Route("[controller]/[action]")]
public class UserController:ControllerBase
{
    private readonly UserManager<IdentityUser> _userManager;

    public UserController(UserManager<IdentityUser> userManager)
    {
        _userManager = userManager;
    }

    [HttpPost]
    public async Task<IActionResult> CreateUserAsync(CreateUserDto input)
    {
        IdentityUser user = new IdentityUser();
        user.UserName = input.UserName;
        var result = await _userManager.CreateAsync(user, input.Password);
        return Ok(result);
    }
}

*:Identity默认的密码策略比较复杂,一般会在配置中进行更改:

builder.Services.Configure<IdentityOptions>(opt =>
{
     opt.Password.RequiredLength = 6;
     opt.Password.RequireNonAlphanumeric = false;
     opt.Password.RequireUppercase = false;
     opt.Password.RequireDigit = false;
});

身份验证

也就是常说的登录。常见的方式有两种,一种是cookie/session,一种是jwt

Cookie/Session:

builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme);


//这里注意顺序,Authentication要在Authorization前
app.UseAuthentication();
[Route("api/[controller]")]
[ApiController]
public class AuthController : ControllerBase
{
    private readonly SignInManager<IdentityUser> _signInManager;

    public AuthController(SignInManager<IdentityUser> signInManager)
    {
        _signInManager = signInManager;
    }


    [HttpPost("login")]
    public async Task<IActionResult> Login(LoginUserDto loginUserDto)
    {
        var result = await _signInManager.PasswordSignInAsync(loginUserDto.UserName, loginUserDto.Password, true, false);
        if (result.Succeeded)
        {
            return Ok("登录成功");
        }
        else
        {
            return Ok("登录失败");
        }
    }
}

在控制器类上或者action方法上使用特性[Authorize],此时如果没有登录或登录失败访问这些接口就会报错。

jwt:

builder.Services.AddAuthentication(options => {
    options.DefaultAuthenticateScheme = 	JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
    .AddJwtBearer(options => {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,//是否验证Issuer
            ValidateAudience = true,//是否验证Audience
            ValidateLifetime = true,//是否验证失效时间
            ClockSkew = TimeSpan.FromSeconds(30),
            ValidateIssuerSigningKey = true,//是否验证SecurityKey
            ValidAudience = JwtConst.Audience,//Audience
            ValidIssuer = JwtConst.Issuer,//Issuer,这两项和前面签发jwt的设置一致
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(JwtConst.SecurityKey))//拿到SecurityKey
        };
    });
[HttpPost("login")]
public async Task<IActionResult> Login([FromBody]LoginUserDto loginUserDto)
{
    var result = await _signInManager.PasswordSignInAsync(loginUserDto.UserName, loginUserDto.Password, false, false);

    if (result.Succeeded)
    {
        //定义JWT的Payload部分
        var claims = new[]
        {
            new Claim(ClaimTypes.Name, loginUserDto.UserName)
        };

        //生成token
        var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(JwtConst.SecurityKey));
        var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
        var securityToken = new JwtSecurityToken(
            issuer: JwtConst.Issuer,
            audience: JwtConst.Audience,
            claims: claims,
            expires: DateTime.Now.AddDays(1),
            signingCredentials: creds);

        var token = new JwtSecurityTokenHandler().WriteToken(securityToken);

        //返回token
        return Ok(token);
    }
    else
    {
        return Ok("登录失败");
    }

}

一些浏览器不支持cookie,比如微信小程序。这之后用谁做身份验证各有利弊,一般来说单体项目用cookie,微服务项目用jwt,但最后还是要看实际情况。