2022年12月

折腾了很多天,首先,要用证书登录,别的系统别想了,要么读不到证书,要么读出来点击没反应,无法选择。
要搞定,很简单,装个 windows xp 吧!

装了 windows xp ,登录、申请一切都没问题了。最后,等初审出来,要支付费用,发现支付不了!
怎么办,我开始是用的系统自带的IE,不行,换360浏览器,还是不行。最后:
装 Google Chrome,解决问题!

真不容易啊。不用浪费资源拿一台电脑专门来做这个系统,直接弄个 vmware,装个虚拟机就可以了。虚拟机文件还可以备份,很容易保留。

我们的项目从.net framework 转到 net core webapi,不想改太多代码,特别是身份认证,之前是直接在 QueryString 中传输 token 来认证,各个 action 上有个自定义的 CheckLogin 标签,要改成的 JWT 认证体系,工作量巨大,于是想到利用过滤器来实现自定义的身份认证过程。

先建一个空的 Attribute,不用任何功能,有这个 Attribute 的 Action 表示都需要认证

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class LoginCheckAttribute : Attribute
{
}

然后建一个 IActionFilter

public class AuthFilter : IActionFilter
{
    private const string UnauthorizedMessage = "授权失效或过期,请重新登录。";

    public void OnActionExecuting(ActionExecutingContext context)
    {
        var controllerInfo = context.ActionDescriptor as ControllerActionDescriptor;
        var needcheck = controllerInfo?.EndpointMetadata.Any(_ => _.GetType() == typeof(LoginCheckAttribute)) ?? false;
        if (needcheck)
        {
            var token = context.HttpContext.Request.Query["token"].ToString();

            ApiResult<object>? result = null;
            if (string.IsNullOrEmpty(token))
            {
                result = new() { Code = 888, Message = UnauthorizedMessage };
            }
            else
            {
                var uinfo = Factory.SessionAccess.GetUserByToken(token);//根据token得到用户信息
                if (uinfo == null)
                {
                    result = new() { Code = 888, Message = UnauthorizedMessage };
                }
                else
                {
                    if (uinfo.State != (int)AdminState.enable)
                    {
                        result = new() { Code = 888, Message = "账号无法使用" };
                    }
                    else
                        context.HttpContext.Items["user"] = uinfo;//用户信息存在会话中,供业务逻辑中调用
                }
            }

            if(result != null)
            {
                context.Result = new UnauthorizedObjectResult(result);
            }
        }
    }

    public void OnActionExecuted(ActionExecutedContext context)
    {
    }
}

然后在 program.cs 中加入过滤器:

builder.Services.AddControllers().AddMvcOptions(options => options.Filters.Insert(0, new AuthFilter()));

业务逻辑中需要用到用户信息的地方这样获取:

    public UserDetails? UserInfo
    {
        get
        {
            if (MyHttpContext.Current == null) return null;
            if(MyHttpContext.Current.Items.TryGetValue("user", out var value))
            {
                return value as UserDetails;
            }
            return null;
        }
    }

直接用 扩展

    public static string GetRemoteIPAddress(this HttpContext context, bool allowForwarded = true)
    {
        if (allowForwarded)
        {
            string? header = context.Request.Headers["CF-Connecting-IP"].FirstOrDefault() ?? context.Request.Headers["X-Forwarded-For"].FirstOrDefault();
            if (!string.IsNullOrEmpty(header) && IPAddress.TryParse(header, out var ip))
            {
                return ip.ToString();
            }
        }
        var _ip = context.Connection.RemoteIpAddress;

        string res = "";
        if (_ip != null)
        {
            if (_ip.IsIPv4MappedToIPv6)
                res = _ip.MapToIPv4().ToString();
            else
                res = _ip.ToString();
        }
        return res;
    }

使用:

string ip = HttpContext.GetRemoteIPAddress();