基于.NET6平台开发WebApi(十一)—— 使用JWT进行用户鉴权

基于NET6平台WebApi尝鲜项目: 基于最新的.NET6平台,完全抛弃繁杂的接口,采用.NET最经典的三层架构,结合简化的DDD设计模式... (gitee.com)

至此我们的项目已经可以正常运行了,但是聪明的你可能发现了一个问题,那就是我们在第九章中将控制器基类中的[Authorize]标记注释掉了,而且我们添加了一个CurrentUserId属性,没错,它就是为了用户鉴权使用的。用户登录可以说是WebApi必不可少的功能,本篇我们就来详细说说如何进行用户鉴权。

1、对于小型项目或者个人项目来说,可能规模比较小,而且不需要单点登录这样的功能,也就没有必要去单独建设一个IdentityServer服务器来实现鉴权,此处我们可以直接使用.NET自带的功能来实现JWT签发,首先我们打开Nuget,搜索安装Microsoft.AspNetCore.Authentication.JwtBearer。

2、接着我们在appsettings.json中配置一个key用于JWT签发,然后打开Program.cs,添加如下代码

#region 添加校验
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
{
    options.TokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuer = true,
        ValidateAudience = true,
        ValidateLifetime = true,
        ValidateIssuerSigningKey = true,
        ValidAudience = "net6api.com",
        ValidIssuer = "net6api.com",
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["JwtSecurityKey"])),
    };
});
#endregion
app.UseAuthentication();
app.UseAuthorization();

3、接下来我们创建一个LoginDto类用于用户登录信息输入,一个LoginView用于用户登录信息返回,代码如下

namespace NET6.Domain.Dtos
{
    /// <summary>
    /// 用户登录
    /// </summary>
    public class LoginDto
    {
        /// <summary>
        /// 登录名
        /// </summary>
        public string LoginName { get; set; }
        /// <summary>
        /// 密码
        /// </summary>
        public string Password { get; set; }
    }
}
namespace NET6.Domain.ViewModels
{
    /// <summary>
    /// 登录信息
    /// </summary>
    public class LoginView
    {
        /// <summary>
        /// token
        /// </summary>
        public string Token { get; set; }
        /// <summary>
        /// 过期时间
        /// </summary>
        public DateTime Expires { get; set; }
        /// <summary>
        /// 用户Id
        /// </summary>
        public string Id { get; set; }
        /// <summary>
        /// 用户名称
        /// </summary>
        public string Name { get; set; }
        /// <summary>
        /// 用户头像
        /// </summary>
        public string Avatar { get; set; }
    }
}

4、接着我们创建一个新的控制器,命名为AuthController,同样继承于BaseController,添加一个登录方法,并且假设我们用户信息已经验证成功,我们给登录方法加上[AllowAnonymous]标记并将BaseController中的[Authorize]标记启用,代码如下

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using NET6.Domain.Dtos;
using NET6.Domain.ViewModels;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

namespace NET6.Api.Controllers
{
    /// <summary>
    /// 鉴权相关
    /// </summary>
    public class AuthController : BaseController
    {
        readonly IConfiguration _config;
        public AuthController(IConfiguration config)
        {
            _config = config;
        }

        /// <summary>
        /// 用户登录
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [AllowAnonymous]
        [HttpPost("login")]
        [ProducesResponseType(typeof(LoginView), StatusCodes.Status200OK)]
        public async Task<IActionResult> LoginAsync(LoginDto dto)
        {
            #region 校验用户信息,假设此处我们已经校验成功

            #endregion
            var view = new LoginView
            {
                Expires = DateTime.Now.AddDays(30)
            };
            var claims = new[] { new Claim(ClaimTypes.NameIdentifier, "") };
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["JwtSecurityKey"]));
            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
            var token = new JwtSecurityToken(
                issuer: "net6api.com",
                audience: "net6api.com",
                claims: claims,
                expires: view.Expires,
                signingCredentials: creds);
            view.Token = new JwtSecurityTokenHandler().WriteToken(token);
            return Ok(JsonView(view));
        }
    }
}

4、编译运行,我们直接访问http://localhost:58707/address?page=1&size=15,发现返回401,表明请求未授权。

5、我们访问用户登录接口,获取Token。

6、我们使用Token再次访问接口,发现鉴权通过,接口正常返回。

7、一切搞定之后我们该如何获取用户信息呢,直接访问我们在BaseController中定义的CurrentUserId即可(可以将更多的信息添加到Token中,在此处同样可以获取)。

 

posted @ 2022-01-07 10:04  昨夜丶雨疏风骤  阅读(3161)  评论(1编辑  收藏  举报