受欢迎的博客标签

ASP.NET Core Web API Authentication series: using JWT Token step by step

Published

.Net 3.x

User DB - either Identity or custom store
Authorize your web api controller
Use JWT for generating JSON web token and validating them.
Provide access if only JWT validates. Excellent support in ASP.NET Core API
Provide Login (token generator API endpoint), pass JWT for further API calls as Authorization header

 

The flow seems to be:

A user visits your site
They see your client app (Angular/React etc.) login page
They submit their username/password
Your client app sends these credentials over to your ASP.NET Core web API (to an action whose sole job is to issue JWT tokens)
The web API checks the credentials against a user store (often a database)
If the credentials are valid
Your web API issues a JWT token back to the client app

 

在asp .net core 程序中,实现认证有以下几种方式,开发时,需选择其中的一种。这次,我们选择JWT认证方式。

Microsoft.AspNetCore.Authentication
Microsoft.AspNetCore.Authentication.Cookies
Microsoft.AspNetCore.Authentication.OAuth
Microsoft.AspNetCore.Authentication.OpenIdConnect
Microsoft.AspNetCore.Authentication.JwtBearer

 

JwtBearer 中间件,它重写了 HandleAuthenticateAsync 方法。

大致步骤如下:

读取 Http Request Header 中的 Authorization 信息
读取 Authorization 值里面的 Bearer 信息
验证 Bearer 是否合法,会得到一个 ClaimsPrincipal
使用 ClaimsPrincipal 构建一个 Ticket(票据)
调用 Options.Events.TokenValidated(context),用户可以重写此方法验证Token合法性
返回验证成功

 

Web API JWT 服务端

Step 1:安装所需的NuGet包

打开NuGet包管理器控制台,然后输入如下指令:

Install-Package Microsoft.AspNetCore.Authentication.JwtBearer
Install-Package System.IdentityModel.Tokens.Jwt

 

step 2:在项目根目录“Startup”类,配置JWT验证方式

首先,要将网站的认证方式配置为JWT验证方式。

配置WebAPI之前我先安装一些NuGet包。

安装Nuget包:

using Microsoft.IdentityModel.Tokens;

Microsoft.AspNetCore.Authentication.JwtBearer

 

ConfigureServices method中,添加JWT验证方式代码

 services.AddAuthentication((opts =>
            {
                opts.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                opts.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;  //如果不加这行,将会跳转到/Account/Login,也就是说你可以用视图来处理未登录
            })) //设置验证方式为常量Bearer,即JWTBearer
                .AddJwtBearer(options =>
                {
                    options.TokenValidationParameters = new TokenValidationParameters
                    {
                        ValidateIssuer = true, //验证发行方
                        ValidateAudience = true, //验证听众api
                        ValidateLifetime = true, //验证生存时间
                        ValidateIssuerSigningKey = true, //验证发行方密钥
                        ValidIssuer = Configuration["JwtIssuer"], //发行方
                        ValidAudience = Configuration["JwtAudience"], //听众
                        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["JwtSecurityKey"])) //对称密钥
                    };
                });
 generate token that is valid for 7 days
  public interface IUserService

come from:

https://jasonwatmore.com/post/2019/10/11/aspnet-core-3-jwt-authentication-tutorial-with-example-api

{
  "AppSettings": {
    "Secret": "THIS IS USED TO SIGN AND VERIFY JWT TOKENS, REPLACE IT WITH YOUR OWN SECRET, IT CAN BE ANY STRING"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}
 private string generateJwtToken(User user)
        {
            // generate token that is valid for 7 days
            var tokenHandler = new JwtSecurityTokenHandler();
            var key = Encoding.ASCII.GetBytes(_appSettings.Secret);
            var tokenDescriptor = new SecurityTokenDescriptor
            {
                Subject = new ClaimsIdentity(new[] { new Claim("id", user.Id.ToString()) }),
                Expires = DateTime.UtcNow.AddDays(7),
                SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
            };
            var token = tokenHandler.CreateToken(tokenDescriptor);
            return tokenHandler.WriteToken(token);
        }

 

ASP.NET Core Custom Validate  token JWT Middleware

using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WebApi.Services;

namespace WebApi.Helpers
{
    public class JwtMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly AppSettings _appSettings;

        public JwtMiddleware(RequestDelegate next, IOptions<AppSettings> appSettings)
        {
            _next = next;
            _appSettings = appSettings.Value;
        }

        public async Task Invoke(HttpContext context, IUserService userService)
        {
            var token = context.Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last();

            if (token != null)
                attachUserToContext(context, userService, token);

            await _next(context);
        }

        private void attachUserToContext(HttpContext context, IUserService userService, string token)
        {
            try
            {
                var tokenHandler = new JwtSecurityTokenHandler();
                var key = Encoding.ASCII.GetBytes(_appSettings.Secret);
                tokenHandler.ValidateToken(token, new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(key),
                    ValidateIssuer = false,
                    ValidateAudience = false,
                    // set clockskew to zero so tokens expire exactly at token expiration time (instead of 5 minutes later)
                    ClockSkew = TimeSpan.Zero
                }, out SecurityToken validatedToken);

                var jwtToken = (JwtSecurityToken)validatedToken;
                var userId = int.Parse(jwtToken.Claims.First(x => x.Type == "id").Value);

                // attach user to context on successful jwt validation
                context.Items["User"] = userService.GetById(userId);
            }
            catch
            {
                // do nothing if jwt validation fails
                // user is not attached to context so request won't have access to secure routes
            }
        }
    }
}

 

ASP.NET Core Custom Authorize Attribute

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using WebApi.Entities;

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class AuthorizeAttribute : Attribute, IAuthorizationFilter
{
    public void OnAuthorization(AuthorizationFilterContext context)
    {
        var user = (User)context.HttpContext.Items["User"];
        if (user == null)
        {
            // not logged in
            context.Result = new JsonResult(new { message = "Unauthorized" }) { StatusCode = StatusCodes.Status401Unauthorized };
        }
    }
}

 

Use the [Authorize] attribute on WebApi Controllers
using Microsoft.AspNetCore.Mvc;
using WebApi.Models;
using WebApi.Services;

namespace WebApi.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class UsersController : ControllerBase
    {
        private IUserService _userService;

        public UsersController(IUserService userService)
        {
            _userService = userService;
        }

        [HttpPost("authenticate")]
        public IActionResult Authenticate(AuthenticateRequest model)
        {
            var response = _userService.Authenticate(model);

            if (response == null)
                return BadRequest(new { message = "Username or password is incorrect" });

            return Ok(response);
        }

        [Authorize]
        [HttpGet]
        public IActionResult GetAll()
        {
            var users = _userService.GetAll();
            return Ok(users);
        }
    }
}

Step 4:配置同源策略CORS

配置同源策略CORS的目的,是设置允许符合条件的网站才能调用我们的web api接口。

 

 

mongodb async

        public virtual async Task<List<Employee>> GetEmployeeByOpenId(string id)
        {
            var query = from ea in this._employeeRepository.Table
                        .Where(ea => ea.AuthorOpenid == id) 
                        select ea;
            var users = query.ToListAsync();
            return await users;
        }

 

客户端JWT

1.首先要进行登录,登录成功会有个token信息,将token保存起来。

2.向web api接口发送请求,每次请求的时候必须带上这个token。

故需要做2次请求(1,登录,拿到token 2,正式向接口请求数据)

 

https://www.tuicool.com/articles/V3qy2qV

 

Useful links

Role based JWT Tokens in ASP.NET Core APIs

 

JWT在ASP.NET Core3.1的实战博客

blog:https://www.cnblogs.com/yixuanhan/p/12593724.html

完整项目下载地址:https://gitee.com/hanyixuan_net/donet-core

 

ASP.NET Core 3.0 - JWT Authentication Tutorial with Example API

ASP.NET Core 3.1 - JWT Authentication Tutorial with Example API

Authentication with client-side Blazor using JWT WebAPI and ASP.NET Core Identity

翻译链接:https://www.cnblogs.com/chen8854/p/11792986.html