网站首页 网站源码
website
站点相关全部源代码,隐藏了一些关于服务器的信息
using System.ComponentModel;
using System.IdentityModel.Tokens.Jwt;
using System.Web;
using AngleSharp;
using Dpz.Core.EnumLibrary;
using Dpz.Core.Public.ViewModel.V4;
using Dpz.Core.Service.ObjectStorage.Services;
using Dpz.Core.Service.V4.Services;
using Dpz.Core.Web.Models;
using Dpz.Core.Web.Pager;
using Ganss.Xss;
using Markdig;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Rendering;
using IConfiguration = Microsoft.Extensions.Configuration.IConfiguration;

#pragma warning disable CS0162

namespace Dpz.Core.Web.Library;

public static class WebToolsExtensions
{
    public static readonly string Version =
        Assembly.GetEntryAssembly()?.GetName().Version?.ToString() ?? "";

    public const string DefaultGroupId = "5e09be6ae22e4d3b7810b6c7";

    public static readonly Dictionary<int, string> Wind = new()
    {
        { 0, "静风" },
        { 1, "软风" },
        { 2, "轻风" },
        { 3, "微风" },
        { 4, "和风" },
        { 5, "清风" },
        { 6, "强风" },
        { 7, "疾风" },
        { 8, "大风" },
        { 9, "强大风" },
        { 10, "超强大风" },
        { 11, "暴风" },
        { 12, "飓风" },
    };

    /// <summary>
    /// 系统启动时间
    /// </summary>
    public static readonly DateTime StartTime = new(2018, 2, 11, 13, 56, 24, DateTimeKind.Local);

    /// <summary>
    /// 根据Identity反射获取当前用户信息
    /// 未授权用户返回 null
    /// </summary>
    /// <param name="principal"></param>
    /// <returns></returns>
    public static VmUserInfo? GetIdentity(this ClaimsPrincipal principal)
    {
        if (principal.IsLogin())
        {
            var userInfo = new VmUserInfo();
            foreach (var claims in principal.Claims)
            {
                var property = typeof(VmUserInfo).GetProperty(claims.Type);
                if (property == null)
                    continue;
                if (property.PropertyType == typeof(DateTime?))
                {
                    property.SetValue(userInfo, DateTime.Parse(claims.Value));
                }
                else if (property.PropertyType == typeof(Sex))
                {
                    var sex = Enum.Parse(typeof(Sex), claims.Value);
                    property.SetValue(userInfo, sex);
                }
                else if (property.PropertyType == typeof(bool?))
                {
                    bool.TryParse(claims.Value, out var result);
                    property.SetValue(userInfo, result);
                }
                else if (property.PropertyType == typeof(Permissions?))
                {
                    if (Enum.TryParse(claims.Value, out Permissions permissions))
                    {
                        property.SetValue(userInfo, permissions);
                    }
                }
                else
                {
                    typeof(VmUserInfo).GetProperty(claims.Type)?.SetValue(userInfo, claims.Value);
                }
            }

            return userInfo;
        }

        return null;
    }

    public static VmUserInfo GetStrictIdentity(this ClaimsPrincipal principal)
    {
        return principal.GetIdentity() ?? throw new InvalidCredentialException();
    }

    public static VmUserInfo? GetIdentity(this HttpContext httpContext, TokenManagement? token)
    {
        if (token?.Secret == null)
        {
            return httpContext.User.GetIdentity();
        }

        var validated = httpContext.ValidationJwtBearer(token);
        if (!validated && httpContext.User.Identity?.IsAuthenticated != true)
            return null;
        return httpContext.User.GetIdentity();
    }

    public static bool ValidationJwtBearer(this HttpContext httpContext, TokenManagement token)
    {
        string? bearerToken = httpContext.Request.Headers["Authorization"];
        bearerToken = bearerToken?.Replace($"{JwtBearerDefaults.AuthenticationScheme} ", "");
        if (!string.IsNullOrEmpty(bearerToken))
        {
            var tokenValidationParameters = new TokenValidationParameters
            {
                ValidIssuer = token.Issuer,
                ValidAudience = token.Audience,
                ValidateIssuer = true,
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(token.Secret)),
                ValidateLifetime = true,
            };
            try
            {
                var principal = new JwtSecurityTokenHandler().ValidateToken(
                    bearerToken,
                    tokenValidationParameters,
                    out var securityToken
                );
                if (
                    principal.Identity?.IsAuthenticated == true
                    && securityToken is JwtSecurityToken jwtSecurityToken
                    && jwtSecurityToken.Header.Alg.Equals(
                        SecurityAlgorithms.HmacSha256,
                        StringComparison.InvariantCultureIgnoreCase
                    )
                )
                {
                    httpContext.User = principal;
                    return true;
                }
            }
            catch (Exception e)
            {
                Log.Logger.Error(e, "validation jwt fail");
                return false;
            }
        }

        return false;
    }

    public static VmUserInfo? GetIdentity(this Controller controller)
    {
        return controller.ViewData["CurrentUser"] as VmUserInfo;
    }

    public static bool IsAdmin(this ClaimsPrincipal principal)
    {
        var identity = principal.GetIdentity();
        if (identity?.Permissions == null)
            return false;
        return (identity.Permissions.Value & Permissions.System) == Permissions.System;
    }

    /// <summary>
    /// 获取当前用户信息
    /// 未授权用户返回 null
    /// </summary>
    /// <param name="context"></param>
    /// <returns></returns>
    public static async Task<VmUserInfo?> GetUserInfo(this HttpContext context)
    {
        var auth = await context.AuthenticateAsync(Program.AuthorizeCookieName);
        if (auth.Succeeded && auth.Principal?.IsLogin() == true)
        {
            return auth.Principal.GetIdentity();
        }

        return null;
    }

    public static bool IsLogin(this ClaimsPrincipal? principal)
    {
        return principal?.Identity?.IsAuthenticated == true;
    }

    /// <summary>
    /// 获取SessionId
    /// </summary>
    /// <param name="controller"></param>
    /// <returns></returns>
    public static string? SessionId(this Controller controller)
    {
        return controller.ViewData["SessionId"]?.ToString();
    }

    /// <summary>
    /// 获取IP地址
    /// </summary>
    /// <param name="request"></param>
    /// <returns></returns>
    public static string GetIpAddress(this HttpRequest? request)
    {
        if (request == null)
            return "";
#if DEBUG
        return "113.110.235.52";
#endif
        var xff = request.Headers["X-Forwarded-For"];
        return string.IsNullOrEmpty(xff)
            ? request.HttpContext.Connection.RemoteIpAddress?.ToString()
            : xff.ToString();
    }

    /// <summary>
    /// 设置标题
    /// </summary>
    /// <param name="controller"></param>
    /// <param name="title"></param>
    public static void SetTitle(this Controller controller, string title)
    {
        controller.ViewData["Title"] = $"{title} - 叫我阿胖";
    }

    /// <summary>
    /// 是否为ajax请求
    /// </summary>
    /// <param name="request"></param>
    /// <returns></returns>
    public static bool IsAjax(this HttpRequest request)
    {
        var with = request.Headers["X-Requested-With"];
        return string.Equals(with, "XMLHttpRequest", StringComparison.OrdinalIgnoreCase);
    }

    public static async Task<List<SelectListItem>> ArticleTagsAsync(
        this IArticleService articleService
    )
    {
        var tags = await articleService.GetAllTagsAsync();
        return tags.Select(x => new SelectListItem(x, x)).ToList();
    }

    /// <summary>
    /// 获取枚举描述
    /// </summary>
    /// <param name="e"></param>
    /// <returns></returns>
    public static string GetDescription(this Enum e)
    {
        var value = e.ToString();
        var attribute = e.GetType().GetField(value)?.GetCustomAttribute<DescriptionAttribute>();
        return attribute?.Description ?? "";
    }

    /// <summary>
    /// 个性化显示文件大小
    /// </summary>
    /// <param name="length"></param>
    /// <returns></returns>
    public static string FileSize(this long length)
    {
        var sizeText = length + " bytes";
        if (length > 1024m && length < 1024m * 1024m * 3)
        {
            sizeText = (length / 1024m).ToString("F") + " KB";
        }
        else if (length > 1024m * 1024m * 3 && length < 1024m * 1024m * 1024m)
        {
            sizeText = (length / 1024m / 1024m).ToString("F") + " MB";
        }
        else if (length > 1024m * 1024m * 1024m)
        {
            sizeText = (length / 1024m / 1024m / 1024m).ToString("F") + " GB";
        }

        return sizeText;
    }

    public static Dictionary<string, List<string>> GetPublicAction()
    {
        var controllers = Assembly
            .GetExecutingAssembly()
            .GetExportedTypes()
            .Where(x => x.Namespace == "Dpz.Core.Web.Controllers");
        var actions = controllers.ToDictionary(
            x => x.Name,
            x =>
            {
                return x.GetMethods()
                    .Where(y =>
                        y.IsPublic
                        && y.ReturnType == typeof(Task<IActionResult>)
                        && y.GetCustomAttribute<CheckAuthorizeAttribute>() == null
                    )
                    .Select(y => y.Name)
                    .ToList();
            }
        );
        return actions;
    }

    public static object ToGridManagerSource<T>(this IPagedList<T> source)
    {
        return new { totals = source.TotalItemCount, data = source };
    }

    public static IHtmlSanitizer CustomHtmlSanitizer(this IConfiguration configuration)
    {
        var sanitizer = new HtmlSanitizer();

        var rule = configuration.GetSection("XSS").Get<CrossSiteRule>();
        if (rule != null)
        {
            if (rule.Attributes?.Add?.Length > 0)
            {
                rule.Attributes.Add.ForEach(x => sanitizer.AllowedAttributes.Add(x));
            }

            if (rule.Attributes?.Remove?.Length > 0)
            {
                rule.Attributes.Remove.ForEach(x => sanitizer.AllowedAttributes.Remove(x));
            }

            if (rule.Tags?.Add?.Length > 0)
            {
                rule.Tags.Add.ForEach(x => sanitizer.AllowedTags.Add(x));
            }

            if (rule.Tags?.Remove?.Length > 0)
            {
                rule.Tags.Remove.ForEach(x => sanitizer.AllowedTags.Remove(x));
            }

            if (rule.CssProperties?.Add?.Length > 0)
            {
                rule.CssProperties.Add.ForEach(x => sanitizer.AllowedCssProperties.Add(x));
            }

            if (rule.CssProperties?.Remove?.Length > 0)
            {
                rule.CssProperties.Remove.ForEach(x => sanitizer.AllowedAttributes.Remove(x));
            }
        }

        return sanitizer;
    }

    /// <summary>
    /// 从markdown转成html,并从html内容中清除链接的跳转平台,并且在新标签页打开
    /// </summary>
    /// <param name="content"></param>
    /// <returns></returns>
    public static async Task<string> ClearLinkAsync(this string content)
    {
        var pipeline = new MarkdownPipelineBuilder()
            .UsePipeTables()
            .UseTaskLists()
            .UseEmphasisExtras()
            .UseAutoIdentifiers()
            .UseAdvancedExtensions()
            .DisableHtml()
            .Build();
        var detail = Markdown.ToHtml(content, pipeline);
        var context = BrowsingContext.New(Configuration.Default);
        var document = await context.OpenAsync(y => y.Content(detail));
        var images = document.GetElementsByTagName("img");
        foreach (var image in images)
        {
            var src = image.GetAttribute("src");
            image.SetAttribute("class", "lazy");
            image.SetAttribute("loading", "lazy");
            image.SetAttribute("src", $"{Program.CdnBaseAddress}/loaders/bars.svg");
            image.SetAttribute("data-src", src ?? $"{Program.CdnBaseAddress}/images/notfound.png");
        }

        var links = document.GetElementsByTagName("a");
        foreach (var item in links)
        {
            var href = item.GetAttribute("href");
            if (href != null)
            {
                var uri = new Uri(href);
                var parameters = HttpUtility.ParseQueryString(uri.Query);
                var target = parameters["target"];
                if (!string.IsNullOrEmpty(target))
                {
                    item.SetAttribute("href", target);
                }

                item.SetAttribute("target", "_blank");
            }
        }

        return document.Body?.InnerHtml ?? "";
    }

    /// <summary>
    /// 构建https的URI
    /// </summary>
    /// <param name="url"></param>
    /// <returns></returns>
    public static string ForceHttps(this string url)
    {
        var uri = new UriBuilder(url);

        var hadDefaultPort = uri.Uri.IsDefaultPort;
        uri.Scheme = Uri.UriSchemeHttps;
        uri.Port = hadDefaultPort ? -1 : uri.Port;

        return uri.ToString();
    }

    public static async Task DeleteMusicAsync(
        this IObjectStorageOperation objectStorageService,
        VmMusic music
    )
    {
        if (music == null)
            throw new ArgumentNullException(nameof(music));
        if (string.IsNullOrEmpty(music.MusicUrl))
            throw new ArgumentException(
                "property MusicUrl is empty or null",
                nameof(music.MusicUrl)
            );

        await objectStorageService.DeleteAsync(music.MusicUrl);

        if (!string.IsNullOrEmpty(music.CoverUrl))
            await objectStorageService.DeleteAsync(music.CoverUrl);

        if (!string.IsNullOrEmpty(music.LyricUrl))
            await objectStorageService.DeleteAsync(music.LyricUrl);
    }

    public static string GetUpyunHost(this IConfiguration configuration)
    {
        var host = configuration["upyun:Host"];
        if (string.IsNullOrEmpty(host))
            throw new Exception("no upyun.Host node");
        return host;
    }

    public static ModelStateResult CheckModelState(this ModelStateDictionary modelState)
    {
        if (modelState.IsValid)
        {
            var messages = modelState
                .SelectMany(x => x.Value?.Errors ?? new ModelErrorCollection())
                .Select(x => x.ErrorMessage)
                .Where(x => !string.IsNullOrEmpty(x))
                .ToList();
            if (messages.Count == 0)
            {
                return new ModelStateResult(false, []);
            }

            return new ModelStateResult(true, messages);
        }

        return new ModelStateResult(false, []);
    }
}
⚠⚠    以下内容为AI分析的结果,请根据实际情况进行判断。

上述代码是一个 C# 类库,名为 WebToolsExtensions,它包含了一系列的扩展方法和工具函数,主要用于 ASP.NET Core Web 应用程序的开发。以下是对代码中各个部分功能的详细解释:

1. 常量和字段

  • Version: 获取当前应用程序的版本。
  • DefaultGroupId: 定义一个默认的组 ID。
  • Wind: 一个字典,映射风速等级到中文描述。
  • StartTime: 系统启动时间的静态字段。

2. 用户身份相关方法

  • GetIdentity: 从 ClaimsPrincipal 中提取用户信息,返回一个 VmUserInfo 对象。如果用户未登录,则返回 null
  • GetStrictIdentity: 获取用户身份信息,如果未登录则抛出 InvalidCredentialException
  • GetIdentity (HttpContext): 根据提供的 TokenManagement 验证 JWT 令牌并获取用户身份信息。
  • ValidationJwtBearer: 验证 JWT 令牌的有效性,设置 HttpContext.User
  • GetIdentity (Controller): 从控制器的 ViewData 中获取当前用户信息。

3. 权限和登录状态检查

  • IsAdmin: 检查当前用户是否具有管理员权限。
  • IsLogin: 检查用户是否已登录。

4. 请求和会话相关方法

  • GetUserInfo: 获取当前用户信息,基于 Cookie 认证。
  • SessionId: 获取当前会话 ID。
  • GetIpAddress: 获取请求的 IP 地址,支持 X-Forwarded-For 头。

5. 视图和 AJAX 相关方法

  • SetTitle: 设置页面标题。
  • IsAjax: 检查请求是否为 AJAX 请求。

6. 文章标签和枚举描述

  • ArticleTagsAsync: 异步获取文章标签并返回 SelectListItem 列表。
  • GetDescription: 获取枚举值的描述属性。

7. 文件大小格式化

  • FileSize: 将文件大小(以字节为单位)格式化为可读的字符串(如 KB、MB、GB)。

8. 控制器公共操作

  • GetPublicAction: 获取所有公共控制器操作的方法,返回一个字典,键为控制器名称,值为方法名称列表。

9. 网页数据源转换

  • ToGridManagerSource: 将分页列表转换为适合 GridManager 的数据源格式。

10. HTML 清理和 Markdown 转换

  • CustomHtmlSanitizer: 创建一个自定义的 HTML 清理器,基于配置文件中的规则。
  • ClearLinkAsync: 将 Markdown 内容转换为 HTML,并清理链接,确保在新标签页中打开。

11. URI 处理

  • ForceHttps: 将给定的 URL 强制转换为 HTTPS。

12. 音乐文件删除

  • DeleteMusicAsync: 异步删除音乐及其相关文件(封面、歌词)。

13. 配置获取

  • GetUpyunHost: 从配置中获取 Upyun 的主机地址。

14. 模型状态检查

  • CheckModelState: 检查模型状态是否有效,并返回相应的结果。

总结

这个类库提供了多种实用的扩展方法,旨在简化 ASP.NET Core Web 应用程序中的常见任务,如用户身份验证、请求处理、数据格式化、HTML 清理等。通过这些工具,开发人员可以更高效地构建和维护 Web 应用程序。

loading