准备工作:
- 依赖项:Microsoft.AspNetCore.Authentication.JwtBearer
用于创建Jwt密匙和发布信息,放在appsetting.json中,注入依赖IConfiguration时选择Microsoft.Extensions.Configuration - 依赖项:Microsoft.AspNetCore.Identity.EntityFrameworkCore
用于身份认证,获取用户等identity操作。框架内包含signInManager、userManager - 使用方法:
- 首先先要创建用户类,我们选择继承identity.EntityFrameworkCore提供的IdentityUser类创建新的用户类,该用户类下以Address作为标记,绑定购物车、订单、角色集合,后续还会添加Token等信息
public class ApplicationUser : IdentityUser
{
public string Address { get; set; }
public ShoppingCart ShoppingCart { get; set; }
public ICollection<Order> Orders { get; set; }
public virtual ICollection<IdentityUserRole<string>> UserRoles { get; set; }
}
- 之后创建JwtHelper类,通过identity框架获取用户信息并为之创建Token
public static class JwtHelper
{
public static async Task<string> JwtCreaterAsync(UserManager<ApplicationUser> _userManager, IConfiguration _configuration, ApplicationUser user)//此处的model类型可以更换
{
// 2 创建jwt
// header
// payload
var claims = new List<Claim>
{
// sub
new Claim(JwtRegisteredClaimNames.Sub, user.Id),
//new Claim(ClaimTypes.Role, "Admin")
};
var roleNames = await _userManager.GetRolesAsync(user);
foreach (var roleName in roleNames)
{
var roleClaim = new Claim(ClaimTypes.Role, roleName);
claims.Add(roleClaim);
}
// signiture
var signingCredentials = new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Authentication:SecretKey"])),SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
issuer: _configuration["Authentication:Issuer"],
audience: _configuration["Authentication:Audience"],
claims,
notBefore: DateTime.UtcNow,
expires: DateTime.UtcNow.AddDays(1),
signingCredentials
);
var tokenStr = new JwtSecurityTokenHandler().WriteToken(token);
return tokenStr;
}
}
Appsetting中的信息如下:
{"Authentication": {"SecretKey": "suibianzifuchaun","Issuer": "fakexiecheng.com","Audience": "fakexiecheng.com"}}
3. 登录和注册需要用到的两个操作
①验证用户和密码:
// 1 验证用户名密码
var loginResult = await _signInManager.PasswordSignInAsync(
loginDto.Email,
loginDto.Password,
false,
false
);
if(!loginResult.Succeeded)
{
return BadRequest();
}
//通过email或者其他string获取对应的用户
var user = await _userManager.FindByNameAsync(loginDto.Email);
②创建用户对象并存储
// 1 使用用户名创建用户对象
var user = new ApplicationUser()
{
UserName = registerDto.Email,
Email = registerDto.Email
};
// 2 hash密码,保存用户
var result = await _userManager.CreateAsync(user, registerDto.Password);//此处用的identityEntityFreamwork的认证框架,对于密码有要求:必须超过6位、必须带大写字符、小写字符、数字、特殊字符
if(!result.Succeeded)
{
return BadRequest();
}
// 4 return
return Ok();
- 完整的登录和注册方法代码:
using FakeXiecheng.API.Dtos;
using FakeXiecheng.API.Helper;
using FakeXiecheng.API.Models;
using FakeXiecheng.API.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
namespace FakeXiecheng.API.Controllers
{
[ApiController]
[Route("auth")]
public class AuthenticateController : ControllerBase
{
private readonly IConfiguration _configuration;
private readonly UserManager<ApplicationUser> _userManager;
private readonly SignInManager<ApplicationUser> _signInManager;
private readonly ITouristRouteRepository _touristRouteRepository;
public AuthenticateController(
IConfiguration configuration,
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager,
ITouristRouteRepository touristRouteRepository
)
{
_configuration = configuration;
_userManager = userManager;
_signInManager = signInManager;
_touristRouteRepository = touristRouteRepository;
}
[AllowAnonymous]
[HttpPost("login")]
public async Task<IActionResult> Login([FromBody] LoginDto loginDto)
{
// 1 验证用户名密码
var loginResult = await _signInManager.PasswordSignInAsync(
loginDto.Email,
loginDto.Password,
false,
false
);
if(!loginResult.Succeeded)
{
return BadRequest();
}
var user = await _userManager.FindByNameAsync(loginDto.Email);
var tokenStr = await JwtHelper.JwtCreaterAsync(_userManager, _configuration, user);
// 3 return 200 ok + jwt
return Ok(tokenStr);
}
[AllowAnonymous]
[HttpPost("register")]
public async Task<IActionResult> Register([FromBody] RegisterDto registerDto)
{
// 1 使用用户名创建用户对象
var user = new ApplicationUser()
{
UserName = registerDto.Email,
Email = registerDto.Email
};
// 2 hash密码,保存用户
var result = await _userManager.CreateAsync(user, registerDto.Password);
if(!result.Succeeded)
{
return BadRequest();
}
// 3 初始化购物车
var shoppingCart = new ShoppingCart()
{
Id = Guid.NewGuid(),
UserId = user.Id
};
await _touristRouteRepository.CreateShoppingCart(shoppingCart);
await _touristRouteRepository.SaveAsync();
// 4 return
return Ok();
}
}
}
- 服务注入(全程在Startup中)
1、注入Jwt的认证服务
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
byte[] secretByte = Encoding.UTF8.GetBytes(Configuration["Authentication:SecretKey"]);
options.TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = true,//验证发布者
ValidIssuer = Configuration["Authentication:Issuer"],
ValidateAudience = true,//验证Token持有者
ValidAudience = Configuration["Authentication:Audience"],
ValidateLifetime = true,//验证是否过期
IssuerSigningKey = new SymmetricSecurityKey(secretByte)//传入私钥并加密
};
});
2、启动用户授权框架
{
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();//这三部的顺序不能变
app.UseEndpoints(endpoints =>endpoints.MapControllers());//route路径,与认证无关,附此代码是为了确保启动框架顺序正确
}