• .Net5.0 WebApi 注册登录以及基于JWT的简单身份认证与授权


    • 新建一个API的项目

    powershell中执行

    dotnet new webapi

    或者使用Visual Studio 2019

     

    默认的模板已经配置了Swagger中间件,启用Swagger的验证功能,ConfigureServices方法中增加

    services.AddSwaggerGen(c =>
    {
       ...
        c.AddSecurityRequirement(new OpenApiSecurityRequirement
        {
            {
                new OpenApiSecurityScheme
                {
                    Reference = new OpenApiReference
                    {
                        Id = "Bearer",
                        Type = ReferenceType.SecurityScheme
                    }
                }, 
                Array.Empty<string>() 
            } 
        });
        c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
        {
            Description = "Please enter into field the word 'Bearer' followed by a space and the JWT value",
            Name = "Authorization",
            In = ParameterLocation.Header,
            Type = SecuritySchemeType.ApiKey
        });
    });
    • 配置身份认证服务
    1. Configure方法

    app.UseAuthorization()之前增加app.UseAuthentication();

    1. ConfigureServices方法

    增加

    services.AddAuthorization(options =>
    {
        options.AddPolicy(JwtBearerDefaults.AuthenticationScheme, policy =>
        {
            policy.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme);
            policy.RequireClaim(ClaimTypes.Name);
            policy.RequireRole(ClaimTypes.Role);
        });
    });
    services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(options =>
        {
            options.Events = new JwtBearerEvents
            {
                OnTokenValidated = async context =>
                {
                    var userService = context.HttpContext.RequestServices.GetRequiredService<IUserService>();
                    var name = context.Principal.Identity.Name;
                    var user = await userService.GetByNameAysnc(name);
                    if (user == null)
                    {
                        context.Fail("Unauthorized");
                    }
                }
            };
            options.TokenValidationParameters =
                new TokenValidationParameters
                {
                    ValidateAudience = false,
                    ValidateIssuer = false,
                    ValidateActor = false,
                    ValidateLifetime = true,
                    IssuerSigningKey = UsersController.SecurityKey
                };
        });

     

    • 使用mssql数据库
    1. 引入依赖
    <PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.0" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.0">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.0" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.0">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
    1. ConfigureServices方法
    var sqlConnection = Configuration.GetConnectionString("SqlServerConnection");
    services.AddDbContext<WebAPIDBContent>(option => option.UseSqlServer(sqlConnection));
    • 配置数据库
    1. 创建表
    public class User
    {
        [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }
        [Required, MaxLength(64)]
        public string UserName { get; set; }
        [Required, MaxLength(64)]
        public byte[] PasswordHash { get; set; }
        [Required, MaxLength(128)]
        public byte[] PasswordSalt { get; set; }
        [Required, MaxLength(20)]
        public string Phone { get; set; }
        [Required, MaxLength(20)]
        public string UserType { get; set; }
    }
    1. 创建数据库
    public class WebAPIDBContent : DbContext
    {
        public WebAPIDBContent(DbContextOptions<WebAPIDBContent> options) : base(options)
        {
        }
    
        public DbSet<User> Users { get; set; }
    }
    1. .迁移数据库

    数据库连接配置:appsettings.json中增加

      "ConnectionStrings": {
        "SqlServerConnection": "Server=(localdb)\mssqllocaldb;Database=WedAPIServer;Trusted_Connection=True;MultipleActiveResultSets=true"
      },

     程序包管理器控制台中执行

    Add-Migration InitialCreate
    Update-Database
    • 增加用户控制器
    [Authorize(Roles = "Admin")]
    [ApiController]
    [Route("[controller]")]
    public class UsersController : ControllerBase
    {
        public static JwtSecurityTokenHandler JwtTokenHandler = new JwtSecurityTokenHandler();
        public static SymmetricSecurityKey SecurityKey = new SymmetricSecurityKey(Guid.NewGuid().ToByteArray());
    
        private IUserService _userService;
        private IMapper _mapper;
        private IActionContextAccessor _accessor;
        private readonly ILogger<UsersController> _logger;
    
    
        public UsersController(
            ILogger<UsersController> logger,
            IUserService userService,
            IMapper mapper,
            IActionContextAccessor httpContextAccessor)
        {
            _logger = logger;
            _userService = userService;
            _mapper = mapper;
            _accessor = httpContextAccessor;
        }
    
        [AllowAnonymous]
        [HttpPost("authenticate")]
        public async Task<IActionResult> Authenticate(UserDto userDto)
        {
            _logger.LogInformation($"Authenticate {userDto.Username}@{userDto.Password}");
            var user = await _userService.AuthenticateAysnc(userDto.Username, userDto.Password);
    
            if (user == null)
                return BadRequest(new { message = "Username or password is incorrect" });
    
            var claims = new[] { new Claim(ClaimTypes.Name, user.UserName), new Claim(ClaimTypes.Role, user.UserType) };
            var credentials = new SigningCredentials(SecurityKey, SecurityAlgorithms.HmacSha256);
            var token = new JwtSecurityToken("WebAPIServer", "WebAPIClients", claims, expires: DateTime.Now.AddDays(1), signingCredentials: credentials);
            var tokenString = JwtTokenHandler.WriteToken(token);
            return Ok(new
            {
                Type = "Bearer",
                Token = tokenString
            });
        }
    
        [AllowAnonymous]
        [HttpPost("register")]
        public async Task<IActionResult> Register(UserDto userDto)
        {
            _logger.LogInformation($"Register {userDto.Username}@{userDto.Password}@{userDto.Phone}");
            var user = _mapper.Map<User>(userDto);
            try
            {
                var _user = await _userService.CreateAysnc(user, userDto.Password);
                return Ok(_mapper.Map<UserDto>(_user));
            }
            catch (AppException ex)
            {
                _logger.LogWarning($"Register AppException"+ ex.Message);
                return BadRequest(new { message = ex.Message });
            }
        }
    
        [HttpGet]
        public async Task<IActionResult> GetAll()
        {
            _logger.LogInformation($"GetAll");
            var users = await _userService.GetAllAysnc();
        var userDtos = _mapper.Map<List<UserDto>>(users);
        return Ok(userDtos);
    }
    
    [HttpGet("{id}")]
    public async Task<IActionResult> GetById(int id)
    {
        _logger.LogInformation($"GetById {id}");
        var user = await _userService.GetByIdAysnc(id);
        var userDto = _mapper.Map<UserDto>(user);
        return Ok(userDto);
    }
    
    [HttpPut("{id}")]
    public async Task<IActionResult> Update(int id, UserDto userDto)
    {
        _logger.LogInformation($"Update {id} {userDto.Username}@{userDto.Password}@{userDto.Phone}");
        var user = _mapper.Map<User>(userDto);
        user.Id = id;
        try
        {
            await _userService.UpdateAysnc(user, userDto.Password);
            return Ok();
        }
        catch (AppException ex)
        {
            return BadRequest(new { message = ex.Message });
        }
    }
    
    [HttpDelete("{id}")]
    public async Task<IActionResult> Delete(int id)
    {
        _logger.LogInformation($"Delete {id}");
        await _userService.DeleteAysnc(id);
        return Ok();
    }
    • 测试
    1. 注册一个管理员账户

    1. 登录,获取token

    1. 点击右上角的Authorize填写token

    1. 成功调用其他API

     调用Get/Users API 时,如果未登录,返回401,如果登录的不是管理员账户(用户类型Admin),返回403

     项目地址:https://gitee.com/ALittleDruid/WebAPIServer

  • 相关阅读:
    CF979D Kuro and GCD and XOR and SUM(01Trie)
    2020中国计量大学校赛题解
    CF16E Fish (状压dp)
    2017ccpc杭州站题解
    HDU6274 Master of Sequence(二分+预处理)
    CF899F Letters Removing(树状数组+二分)
    牛客 tokitsukaze and Soldier(优先队列+排序)
    HDU6268 Master of Subgraph(点分治)
    CF862E Mahmoud and Ehab and the function(二分)
    CF1108F MST Unification(生成树+思维)
  • 原文地址:https://www.cnblogs.com/colorchild/p/14515519.html
Copyright © 2020-2023  润新知