网站首页 网站源码
website
站点相关全部源代码,隐藏了一些关于服务器的信息
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using Dpz.Core.Public.ViewModel.Request;
using Dpz.Core.Public.ViewModel.Response;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;

namespace Dpz.Core.Service.RepositoryServiceImpl;

public class TokenAuthenticationService(
    IAccountService accountService,
    IOptions<TokenManagement> tokenManagement,
    IAccountTokenService accountTokenService,
    IAppOptionService optionService,
    ILogger<TokenAuthenticationService> logger,
    IConfiguration configuration
) : IAuthenticateService
{
    private readonly TokenManagement _tokenManagement = tokenManagement.Value;

    /// <summary>
    /// 验证
    /// </summary>
    /// <returns></returns>
    public async Task<AuthenticatedResponse?> AuthenticatedAsync(AuthenticateRequest request)
    {
        var userInfo = await accountService.LoginAsync(request.Account, request.Md5Password);
        if (userInfo == null)
            return null;

        if (!userInfo.Avatar.StartsWith("http", StringComparison.CurrentCultureIgnoreCase))
        {
            userInfo.Avatar = configuration["WebHost"] + userInfo.Avatar;
        }

        var accessToken = GenerateAccessToken(userInfo);

        var accountTokenRequest = new AccountTokenRequest
        {
            Account = request.Account,
            ExpiresTime = DateTime.Now.AddDays(_tokenManagement.RefreshExpiration),
            Platform = request.Platform,
            IpAddress = request.IpAddress,
            UserAgent = request.UserAgent
        };
        var refreshToken = await accountTokenService.GenerateRefreshTokenAsync(accountTokenRequest);

        return new AuthenticatedResponse(
            accessToken.expires,
            accessToken.token,
            refreshToken,
            userInfo
        );
    }

    /// <summary>
    /// 生成访问令牌
    /// </summary>
    /// <param name="userInfo"></param>
    /// <returns></returns>
    private (DateTime expires, string token) GenerateAccessToken(VmUserInfo userInfo)
    {
        var claims = userInfo
            .GetType()
            .GetProperties()
            .Select(x => new Claim(x.Name, x.GetValue(userInfo)?.ToString() ?? ""))
            .ToList();
        claims.Add(new Claim(ClaimTypes.Name, userInfo.Id));
        var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_tokenManagement.Secret));
        var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
        var expires = DateTime.Now.AddMinutes(_tokenManagement.AccessExpiration);
        var jwtToken = new JwtSecurityToken(
            issuer: _tokenManagement.Issuer,
            audience: _tokenManagement.Audience,
            claims: claims,
            expires: expires,
            signingCredentials: credentials
        );
        var token = new JwtSecurityTokenHandler().WriteToken(jwtToken);
        return (expires, token);
    }

    /// <summary>
    /// 刷新token
    /// </summary>
    /// <returns></returns>
    public async Task<AuthenticatedResponse?> RefreshTokenAsync(RefreshTokenRequest request)
    {
        var tokenValidationParameters = new TokenValidationParameters
        {
            ValidIssuer = _tokenManagement.Issuer,
            ValidAudience = _tokenManagement.Audience,
            ValidateIssuer = true,
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = new SymmetricSecurityKey(
                Encoding.UTF8.GetBytes(_tokenManagement.Secret)
            ),
            // 忽略token过期时间,验证token
            ValidateLifetime = false
        };
        var principal = new JwtSecurityTokenHandler().ValidateToken(
            request.AccessToken,
            tokenValidationParameters,
            out var securityToken
        );
        if (
            principal.Identity?.IsAuthenticated != true
            || securityToken is not JwtSecurityToken jwtSecurityToken
            || !jwtSecurityToken.Header.Alg.Equals(
                SecurityAlgorithms.HmacSha256,
                StringComparison.InvariantCultureIgnoreCase
            )
        )
        {
            logger.LogError("refresh token fail,stack trace:{StackTrace}", Environment.StackTrace);
            return null;
        }

        var account = principal.Identity?.Name ?? "";
        if (
            await accountTokenService.ValidateRefreshTokenAsync(
                account,
                request.RefreshToken,
                request.Platform
            )
        )
        {
            var userInfo = await accountService.GetOneUserAsync(account);
            if (!userInfo.Avatar.StartsWith("http", StringComparison.CurrentCultureIgnoreCase))
            {
                userInfo.Avatar = configuration["WebHost"] + userInfo.Avatar;
            }

            var accountTokenRequest = new AccountTokenRequest
            {
                Account = userInfo.Id,
                ExpiresTime = DateTime.Now.AddDays(_tokenManagement.RefreshExpiration),
                Platform = request.Platform,
                IpAddress = request.IpAddress,
                UserAgent = request.UserAgent
            };
            var newAccessToken = GenerateAccessToken(userInfo);
            var newRefreshToken = await accountTokenService.GenerateRefreshTokenAsync(
                accountTokenRequest
            );
            return new AuthenticatedResponse(
                newAccessToken.expires,
                newAccessToken.token,
                newRefreshToken,
                userInfo
            );
        }

        return null;
    }

    /// <summary>
    /// 登入
    /// </summary>
    /// <returns></returns>
    public async Task<string?> SignInAsync(string account, string password)
    {
        //VmUserInfo user, VmSaltOption salt
        var userInfo = await accountService.LoginAsync(account, (account + password).GenerateMd5());
        if (userInfo == null)
            return null;
        var salt = await optionService.GetSaltAsync(account);
        var claims = userInfo
            .GetType()
            .GetProperties()
            .Select(x => new Claim(x.Name, x.GetValue(userInfo)?.ToString() ?? ""))
            .ToList();
        claims.Add(new Claim(ClaimTypes.Name, userInfo.Id));
        var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(salt.Salt));
        var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
        var expires = salt.Expire;
        var jwtToken = new JwtSecurityToken(
            issuer: "api-server",
            audience: "api-client",
            claims: claims,
            expires: expires,
            signingCredentials: credentials
        );
        var token = new JwtSecurityTokenHandler().WriteToken(jwtToken);
        return token;
    }
}
⚠⚠    以下内容为AI分析的结果,请根据实际情况进行判断。

上述代码是一个实现了身份验证服务的 C# 类 TokenAuthenticationService,它使用 JWT(JSON Web Tokens)来处理用户的身份验证和令牌管理。以下是代码的主要功能和结构的详细解释:

1. 类的构造函数

TokenAuthenticationService 类的构造函数接受多个依赖项,包括:

  • IAccountService:用于处理用户账户相关的操作,如登录。
  • IOptions<TokenManagement>:用于获取令牌管理的配置(如密钥、过期时间等)。
  • IAccountTokenService:用于处理与令牌相关的操作,如生成和验证刷新令牌。
  • IAppOptionService:用于获取应用程序的选项配置。
  • ILogger<TokenAuthenticationService>:用于记录日志。
  • IConfiguration:用于访问应用程序的配置设置。

2. 认证方法

AuthenticatedAsync

  • 功能:处理用户的登录请求,验证用户凭据,并生成访问令牌和刷新令牌。
  • 流程
    1. 调用 accountService.LoginAsync 方法验证用户的账户和密码。
    2. 如果用户信息有效,生成访问令牌(JWT)和刷新令牌。
    3. 返回一个 AuthenticatedResponse 对象,包含访问令牌、刷新令牌和用户信息。

GenerateAccessToken

  • 功能:生成访问令牌(JWT)。
  • 流程
    1. 从用户信息中提取声明(Claims)。
    2. 使用对称密钥和 HMAC SHA256 算法进行签名。
    3. 设置令牌的过期时间。
    4. 返回令牌及其过期时间。

3. 刷新令牌方法

RefreshTokenAsync

  • 功能:处理刷新令牌的请求,生成新的访问令牌。
  • 流程
    1. 验证传入的访问令牌。
    2. 检查刷新令牌的有效性。
    3. 如果有效,生成新的访问令牌和刷新令牌,并返回。

4. 登录方法

SignInAsync

  • 功能:处理用户的登录请求,生成基于盐值的 JWT。
  • 流程
    1. 验证用户凭据。
    2. 获取用户的盐值并生成基于盐的 JWT。
    3. 返回生成的 JWT。

5. 其他功能

  • 日志记录:在刷新令牌失败时记录错误信息。
  • 配置管理:使用 IConfiguration 来获取 WebHost 地址,以便构建用户头像的完整 URL。

总结

TokenAuthenticationService 类提供了一整套基于 JWT 的身份验证机制,包括用户登录、访问令牌生成、刷新令牌处理等功能。它通过依赖注入的方式管理服务和配置,确保代码的可维护性和可扩展性。

loading