重庆熊猫 Loading

ASP.NET Core教程-认证配置(token-based authentication)

更新记录
转载请注明出处:
2022年11月2日 发布。
2022年11月1日 从笔记迁移到博客。

认证配置(token-based authentication)

基于Token方式的认证介绍

基于Token方式的认证 和 Session 对比

  • Token方式,服务器端可伸缩性更好。
  • Token方式,状态记录更加方便。

认证生成Token和使用Token流程

  • The client is the application that is trying to access our resources.
  • The identity provider is the service that, given a username and a password, provides an encrypted authentication token.
  • The resource provider is another service called by the client. Furthermore, the resource provider will accept the encrypted authentication token, and it will provide the information requested by the client if it is authorized.

image

JWT认证

基于Token(Token-based authentication)方式的认证很多。JSON Web Token (JWT)是目前最流行的Token认证实现之一。

JWT的作用

  • 认证身份(Authorization): The web service returns a JWT token to transfer information about claims and personal details to signed-in users. Moreover, single sign-on features and token authentication features use this technique to transfer data to the client.
  • 传输数据(Information exchange): You can use the JWT token standard to prevent data exploitation and to certify the authenticity of the data you have received by signing it with the provided key.

JWT格式和组成

JWT的格式为JSON,并包含三部分:标头(header)、有效负载(payload)、签名(signature)。

实例

{
    "alg": "RS256",  
    "kid": "4B92FBAE5D98B4D2AB43ACE4198026073012E17F",  
    "x5t": "S5L7rl2YtNKrQ6zkGYAmBzAS4X8",
    "typ": "JWT"
}.
{  "sub": "john.doe @contoso.com",
    "nbf": 1596035128,
    "exp": 1596038728,
    "iss": "contoso",
    "aud": "MyWebApp"
}
.[Signature]

具体参数解释:
header

  • ''alg'': The algorithm used for generating the signature
  • ''kid'': Key identifier
  • ''x5t'': Key identifier
  • ''typ'': The type of the token

payload

  • ''nbf'': Not before. The time from which the token is valid; - usually the same time as it was issued.
  • ''exp'': Expiration time. The time the token is valid until. Usually an hour from when it was issued (but this is up to the token issuer).
  • ''iss'': Issuer. The issuer of the token.
  • ''aud'': Audience. Who the token is intended for; usually the app the token is intended for

实现基于Token方式的认证(Implementing token-based authentication)

首先为项目安装包

dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
dotnet add package Microsoft.AspNetCore.Identity.EntityFrameworkCore

定义验证相关的服务接口。

using System.Threading;
using System.Threading.Tasks;
using Catalog.Domain.Entities;

namespace Catalog.Domain.Repositories
{
    public interface IUserRepository
    {
        Task<bool> AuthenticateAsync(string email, string password);
        Task<bool> SignUpAsync(User user, string password);
        Task<User> GetByEmailAsync(string requestEmail);
    }
}

实现验证相关的服务


定义JWT服务

using System.Text;
using Catalog.Domain.Configurations;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
namespace Catalog.Infrastructure.Extensions
{
    public static class AuthenticationExtensions
    {
        //扩展方法
        public static IServiceCollection AddTokenAuthentication(this IServiceCollection services, IConfiguration configuration)
        {
            //获得配置信息
            var settings = configuration.GetSection("AuthenticationSettings");
            
            var settingsTyped = settings.Get<AuthenticationSettings>();

            services.Configure<AuthenticationSettings>(settings);
            var key = Encoding.ASCII.GetBytes(settingsTyped.Secret);
            services.AddAuthentication(x =>
                {
                    x.DefaultAuthenticateScheme = 
                        JwtBearerDefaults.AuthenticationScheme;
                    x.DefaultChallengeScheme = 
                        JwtBearerDefaults.AuthenticationScheme;
                })
                .AddJwtBearer(x =>
                {
                    x.TokenValidationParameters = new 
                        TokenValidationParameters
                        {
                            IssuerSigningKey = new 
                                SymmetricSecurityKey(key),
                            ValidateIssuer = false,
                            ValidateAudience = false
                        };
                });
            return services;
        }
    }
}

在 appsettings.json 中定义验证相关的配置

...
"AuthenticationSettings": {
    "Secret": "My Super long secret",
    "ExpirationDays": "7"
}
...

注册验证服务和增加验证中间件

namespace Catalog.API
{
    public class Startup
    {
        public Startup(IConfiguration configuration, 
        IWebHostingEnvironment environment)
        {
            Configuration = configuration;
            CurrentEnvironment = environment;
        }

        ...
        public void ConfigureServices(IServiceCollection services)
        {
            ...
            //注册服务
            services.AddTokenAuthentication(Configuration)
             
            ...
        }

        public void Configure(IApplicationBuilder app, 
        IHostingEnvironment env)
        {
            ...
            //增加验证中间件
            app.UseAuthentication();
            app.UseAuthorization();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
}

定义生成Token方法

private string GenerateSecurityToken(SignInRequest request)
{
    var tokenHandler = new JwtSecurityTokenHandler();
    var key = Encoding.ASCII.GetBytes(_authenticationSettings.Secret);

    var tokenDescriptor = new SecurityTokenDescriptor
    {
        Subject = new ClaimsIdentity(new[]
        {
            new Claim(ClaimTypes.Email, request.Email)
        }),
        Expires = 
        DateTime.UtcNow.AddDays
        (_authenticationSettings.ExpirationDays),
        SigningCredentials = new SigningCredentials(new 
        SymmetricSecurityKey(key), 
            SecurityAlgorithms.HmacSha256Signature)
    };

    var token = tokenHandler.CreateToken(tokenDescriptor);
    return tokenHandler.WriteToken(token);
}

设置控制器验证身份(Applying authentication on the controller)

using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Catalog.API.Filters;
using Catalog.Domain.Requests.User;
using Catalog.Domain.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace Catalog.API.Controllers
{
    //设置为必须验证身份
    [Authorize]      
    [ApiController]
    [Route("api/user")]
    [JsonException]
    public class UserController : ControllerBase
    {
        private readonly IUserService _userService;

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

        [HttpGet]
        public async Task<IActionResult> Get()
        {
            var claim = HttpContext.User.Claims.FirstOrDefault(x => 
                x.Type == ClaimTypes.Email);

            if (claim == null) return Unauthorized();

            var token = await _userService.GetUserAsync(new 
                GetUserRequest { Email = claim.Value });
            return Ok(token);
        }

        //设置为可以匿名访问
        [AllowAnonymous]
        [HttpPost("auth")]
        public async Task<IActionResult> SignIn(SignInRequest request)
        {
            var token = await _userService.SignInAsync(request);
            if (token == null) return BadRequest();
            return Ok(token);
        }

        [AllowAnonymous]
        [HttpPost]
        public async Task<IActionResult> SignUp(SignUpRequest request)
        {
            var user = await _userService.SignUpAsync(request);
            if (user == null) return BadRequest();
            return CreatedAtAction(nameof(Get), new { }, null);
        }
    }
}
posted @ 2022-11-02 09:09  重庆熊猫  阅读(424)  评论(0编辑  收藏  举报