网站首页 网站源码
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;
    }
}
loading