清风博客 https://www.skyfinder.cc 关注IT世界,记录平凡生活 Thu, 14 Jan 2021 04:43:44 +0000 zh-CN hourly 1 https://wordpress.org/?v=5.6 急性上呼吸道感染 https://www.skyfinder.cc/2021/01/14/influenza/ https://www.skyfinder.cc/2021/01/14/influenza/#respond Thu, 14 Jan 2021 04:42:51 +0000 https://www.skyfinder.cc/?p=3341

最近天气突然骤降,一不小心就生病了,鼻塞、流鼻涕实在难受,随即而来的就是鼻炎复发以及中耳炎。每一次都是这个流程,每一次感冒没有千把块就摆不平,总有一天死在这个上面,也说不准。哎!

急性上呼吸道感染

急性上呼吸道感染,俗称“感冒”主要是指鼻咽和咽部的急性感染。本病是常见的疾病,常诊断为“急性鼻咽炎”、“急性咽炎”、“急性扁桃体炎”等。该病一年四季均可发生,以冬、春季节及气候骤变时多见。

  • 患病期间好好休息、充足睡眠、忌劳累、忌锻炼身体,以保持体力,有利于康复。
  • 多喝水,吃清淡、富含维生素、易消化的食物,如:米汤,豆浆、粥、面条、鸡蛋羹等半流质食物及新鲜蔬菜、水果,忌食油腻、煎炸的食物。
  • 房间经常通风换气,保持适宜的温度,在家里尽量做到床边隔离,避免再传染给他人。
  • 预防胜于治疗:避免受凉、淋雨、过度疲劳;避免与感冒患者接触,避免脏手接触口、眼、鼻。年老体弱易感者更应注意防护,上呼吸道感染流行时应戴口罩,避免在人多的公共场合出入。平时加强体质锻炼、增强抗病能力。必要时注射疫苗。

在医生的指导下用药,切记乱用药,由于上呼吸道感染大多数由病毒引起,一般不必应用抗生素,更不必输液。

转载请注明:清风博客 » 急性上呼吸道感染

]]>
https://www.skyfinder.cc/2021/01/14/influenza/feed/ 0
Visual Studio(VS) Code提示php.executablePath配置问题 https://www.skyfinder.cc/2021/01/07/vs-code-php-executablepath-setting/ https://www.skyfinder.cc/2021/01/07/vs-code-php-executablepath-setting/#respond Thu, 07 Jan 2021 03:22:29 +0000 https://www.skyfinder.cc/?p=3334 Visual Studio Code 安装php插件后提示:

PHP executable not found. Install PHP 7 and add it to your PATH or set the php.executablePath setting

打开VS Code设置查找到php.validate.executablePath进行修改,其值是php安装目录。


{
    "editor.suggestSelection": "first",
    "vsintellicode.modify.editor.suggestSelection": "automaticallyOverrodeDefaultValue",
    "java.semanticHighlighting.enabled": true,
    "php.validate.executablePath": "F:\\phpstudy_pro\\Extensions\\php\\php7.3.4nts"
}

转载请注明:清风博客 » Visual Studio(VS) Code提示php.executablePath配置问题

]]>
https://www.skyfinder.cc/2021/01/07/vs-code-php-executablepath-setting/feed/ 0
ASP.NET Core Web Api实现大文件切/分片上传 https://www.skyfinder.cc/2020/12/31/asp-net-core-big-file-uploader/ https://www.skyfinder.cc/2020/12/31/asp-net-core-big-file-uploader/#respond Thu, 31 Dec 2020 08:15:58 +0000 https://www.skyfinder.cc/?p=3313 一年前的一个项目,有人反馈上传超时,超时原因是文件大小超出限制。由于原来维护项目的人员离开,现在上传超时的问题就有我来处理。解决方案也比较简单,就是切片上传。前端不想自己写了,就利用了上传组件,这个上传组件是百度WebUploaderWebUploader这个组件被使用的也比较广泛,为了省事就用它啦!

上传中

合并后

代码实现

前端代码

前端上传以及分片使用的百度上传组件WebUploader


<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Home Page - WebUpload</title>

    
        <link rel="stylesheet" href="/lib/bootstrap/dist/css/bootstrap.css" />
    
    
    <link rel="stylesheet" href="/css/site.css" />
</head>
<body>
    <header>
        <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
            <div class="container">
                <a class="navbar-brand" href="/">WebUpload</a>
                <button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                        aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
                    <ul class="navbar-nav flex-grow-1">
                        <li class="nav-item">
                            <a class="nav-link text-dark" href="/">Home</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" href="/Home/Privacy">Privacy</a>
                        </li>
                    </ul>
                </div>
            </div>
        </nav>
    </header>
    <div class="container">
        


        <main role="main" class="pb-3">
            <link rel="stylesheet" type="text/css" href="/webuploader/webuploader.css">
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
    <script src="/webuploader/webuploader.js"></script>
    <div class="text-center">
        <h1 class="display-4">Welcome</h1>
        <div id="uploader" class="wu-example">
            <div class="container-fluid">
                <div class="col-md-10">
                    <div class="row">文件上传示例:</div>
                    <div class="row">
                        <div id="uploader" class="wu-example">
                            <!--用来存放文件信息-->
                            <div id="fileList" class="uploader-list"></div>
                            <div class="btns">
                                <div id="picker" class="btn btn-primary">选择文件</div>

                            </div>

                        </div>
                    </div>

                    <div class="row">

                    </div>
                    <div class="row">  <button id="ctlBtn" class="btn btn-default">开始上传</button></div>
                </div>
                <div>
                </div>
            </div>
        </div>
        <p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
    </div>
<script>
    jQuery(function () {
        var $ = jQuery,
            $list = $('#fileList'),
            $btn = $('#ctlBtn'),
            state = 'pending',
            uploader, guid = {};
        uploader = WebUploader.create({
            // 不压缩image
            resize: false,

            // swf文件路径
            swf: "~/webuploader/Uploader.swf",

            server: 'http://localhost:8011/api/File/UplaodFile?isConvert=true',

            // 选择文件的按钮。可选。
            // 内部根据当前运行是创建,可能是input元素,也可能是flash.
            pick: '#picker',
            chunked: true

        });
        
        // 当有文件添加进来的时候
        uploader.on('fileQueued', function (file) {
            guid[file.id] = +(new Date());
            $list.append('<div id="' + file.id + '" class="item">' +
                '<h4 class="info">' + file.name + '</h4>' +
                '<p class="state">等待上传...</p>' +
                '</div>');
            uploader
                .md5File(file)
                .progress(function (percentage) {
                    // console.log("Percentage:", percentage);
                    $("#ctlBtn").hide();
                })
                // MD5计算完毕,可以点击上传了
                .then(function (fileMd5) {
                    file.fileMd5 = fileMd5;
                    $("#ctlBtn").show()
                    console.log(fileMd5);
                });

        });
        uploader.on('uploadBeforeSend', function (file, data, headers) {
            $.extend(data, { "fileId": guid[data.id], "fileMd5": file.file.fileMd5 });
            $.extend(headers, {
                "Authorization":"Bearer "
            });
            if (data.chunks) {
                data["chunkStart"] = file.start;
                data["chunkEnd"] = file.end;
            }
        });
        // 文件上传过程中创建进度条实时显示。
        uploader.on('uploadProgress', function (file, percentage) {

            var $li = $('#' + file.id),
                $percent = $li.find('.progress .progress-bar');
            // 避免重复创建
            if (!$percent.length) {
                $percent = $('<div class="progress progress-striped active">' +
                    '<div class="progress-bar" role="progressbar" style="width: 0%">' +
                    '</div>' +
                    '</div>').appendTo($li).find('.progress-bar');
            }
            $li.find('p.state').text('上传中');
            $percent.css('width', percentage * 100 + '%');

        });

        uploader.on('uploadSuccess', function (file) {
            $('#' + file.id).find('p.state').text('已上传');
        });

        uploader.on('uploadError', function (file) {
            $('#' + file.id).find('p.state').text('上传出错');
        });

        uploader.on('uploadComplete', function (file) {
            $('#' + file.id).find('.progress').fadeOut();
        });
        uploader.on('all', function (type) {
            if (type === 'startUpload') {
                state = 'uploading';
            } else if (type === 'stopUpload') {
                state = 'paused';
            } else if (type === 'uploadFinished') {
                state = 'done';
            }
            if (state === 'uploading') {
                $btn.text('暂停上传');
            } else {
                $btn.text('开始上传');
            }

        });

        $btn.on('click', function () {
            if (state === 'uploading') {
                uploader.stop();
            } else {
                uploader.upload();
            }
        });
    });
</script>

        </main>
    </div>

    <footer class="border-top footer text-muted">
        <div class="container">
            &copy; 2020 - WebUpload - <a href="/Home/Privacy">Privacy</a>
        </div>
    </footer>

    
        <script src="/lib/jquery/dist/jquery.js"></script>
        <script src="/lib/bootstrap/dist/js/bootstrap.bundle.js"></script>
    
    
    <script src="/js/site.js?v=4q1jwFhaPaZgr8WAUSrux6hAuh0XDg9kPS3xIVq36I0"></script>

    
</body>
</html>

后台实现

后台使用的是ASP .NET Core Web API,实现方式也很简单。文件的校验,分块的校验等这里就省略了。
    
    [Route("api/[controller]")]
    public class FileController : Controller
    {
        public static readonly object locker = new object();
        [HttpPost]
        [Route("UplaodFile")]
        public IActionResult UplaodFile([FromForm] IFormCollection form)
        {
            try
            {
                string fileId = form["fileId"];
                if (string.IsNullOrWhiteSpace(fileId)||form.Files==null||form.Files.Count==0)
                {
                    return BadRequest();
                }
                string tempFileFolder = Path.Combine(AppContext.BaseDirectory, $"FileUploader/{fileId}");
                CreateFolder(tempFileFolder);
                if (form.ContainsKey("chunks"))
                {
                    string chunksString = form["chunks"];
                    int chunks = int.Parse(chunksString);
                    string chunkString = form["chunk"];
                    int chunk = int.Parse(chunkString);
                    string sizeString = form["size"];
                    long size = long.Parse(sizeString);
                    string chunkStartString = form["chunkStart"];
                    string chunkEndString = form["chunkEnd"];
                    string chunkMd5 = form["chunkMd5"];
                    string fileMd5 = form["fileMd5"];
                    string lastModifiedDate = form["lastModifiedDate"];
                    var file = form.Files.FirstOrDefault();
                    string name = file.FileName;
                    string ext = Path.GetExtension(name);
                    Stream stream = file.OpenReadStream();
                    byte[] bytes = new byte[stream.Length];
                    stream.Read(bytes, 0, bytes.Length);
                    string factFilePath = Path.Combine(tempFileFolder, $"{name}");
                    string chunkFilePath = $"{factFilePath}.chunk{chunk}";
                    string chunkFileTempPath = $"{chunkFilePath}.temp";
                    System.IO.File.Delete(chunkFileTempPath);
                    FileStream fs = new FileStream(chunkFileTempPath, FileMode.Create);
                    BinaryWriter bw = new BinaryWriter(fs);
                    bw.Write(bytes);
                    bw.Flush();
                    bw.Close();
                    bw.Dispose();
                    fs.Close();
                    fs.Dispose();
                    stream.Close();
                    stream.Dispose();
                    System.IO.File.Move(chunkFileTempPath, chunkFilePath);
                    bool isMerge = true;
                    for (int i = 0; i < chunks; i++)
                    {
                        if (!System.IO.File.Exists($"{factFilePath}.chunk{i}"))
                        {
                            isMerge = false;
                            break;
                        }
                    }

                    if (isMerge)
                    {
                        lock (locker)
                        {
                            if (isMerge)
                            {
                                if (System.IO.File.Exists(factFilePath))
                                {
                                    return Ok();
                                }
                                var fileStream = new FileStream(factFilePath, FileMode.Create);
                                for (int i = 0; i < chunks; i++)
                                {
                                    string chunkFile = $"{factFilePath}.chunk{i}";
                                    var chunkBytes = System.IO.File.ReadAllBytes(chunkFile);
                                    fileStream.Write(chunkBytes, 0, chunkBytes.Length);
                                    fileStream.Flush();
                                    System.IO.File.Delete(chunkFile);//删除分块
                                }
                                fileStream.Close();
                                fileStream.Dispose();
                            }
                        }

                    }
                }
                else
                {
                    var file = form.Files.FirstOrDefault();
                    Stream stream = file.OpenReadStream();
                    byte[] bytes = new byte[stream.Length];
                    stream.Read(bytes, 0, bytes.Length);
                    FileStream fileStream = new FileStream(Path.Combine(tempFileFolder, $"{file.FileName}"), FileMode.Create);
                    BinaryWriter bw = new BinaryWriter(fileStream);
                    bw.Write(bytes);
                    bw.Flush();
                    bw.Close();
                    bw.Dispose();
                    fileStream.Close();
                    fileStream.Dispose();
                    stream.Close();
                    stream.Dispose();
                }
            }
            catch (Exception ex)
            {
                Console.Write(ex);
            }

            return Ok();
        }
        private void CreateFolder(string folderPath)
        {
            if (!Directory.Exists(folderPath))
            {
                Directory.CreateDirectory(folderPath);
            }
        }
        [HttpGet]
        [Route("Index")]
        public IActionResult Index()
        {
            return Ok();
        }
    }

示例下载

.NET CORE大文件分/切片上传示例

转载请注明:清风博客 » ASP.NET Core Web Api实现大文件切/分片上传

]]>
https://www.skyfinder.cc/2020/12/31/asp-net-core-big-file-uploader/feed/ 0
.NET操作达梦数据库编译错误处理 https://www.skyfinder.cc/2020/12/07/dmprovidererrorprocess/ https://www.skyfinder.cc/2020/12/07/dmprovidererrorprocess/#respond Mon, 07 Dec 2020 02:03:58 +0000 https://www.skyfinder.cc/?p=3279 由于客户突然要进行国产化的一个要求,数据库使用更换了国产达梦数据库,将数据由Oracle数据库迁移到达梦数据库。所以,之前基于Oracle处理的一些功能就需要进行一些调整。

使用NuGet 引入达梦数据提供器DmProvider 

引用相关的组件后,就按照套路对已经存在的方法进行相关调整,结果出现了一些编译出错且无论如何调整都无法消除。如下:

错误 CS1705 标识为“Dm, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null”的程序集“Dm”所使用的“System.Runtime, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a”版本高于所引用的标识为“System.Runtime, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a”的程序集“System.Runtime”

通过各种搜索引擎查找一通,最后也没有见到任何处理问题的方法。总觉得国产的某些东西,距大面积商用还有很远的距离。实在没有办法了,就到达梦官方把达梦数据库Windows开发版本下载下来,并加入达梦数据库官方QQ支持群,咨询关于.net framework 4.0的数据库驱动哪里有提供。

根据QQ群的信息回复,在安装目录找到了相关的组件并引用进行尝试,最终错误消失。

至于为什么Nuget上的会出现异常,也没有深入研究。感觉这没有意义!!

转载请注明:清风博客 » .NET操作达梦数据库编译错误处理

]]>
https://www.skyfinder.cc/2020/12/07/dmprovidererrorprocess/feed/ 0
Linux无法访问外网问题 https://www.skyfinder.cc/2020/11/16/linux-net-work/ https://www.skyfinder.cc/2020/11/16/linux-net-work/#respond Mon, 16 Nov 2020 13:30:23 +0000 https://www.skyfinder.cc/?p=3239 一台Linux局域网服务器,突然发现不能访问外网,也许本来就不行,因为没有用到外网,所以只是没有注意到吧!经过测试外网无法访问,内网畅行无阻。如下:

[root@offline-200 services]# wget baidu.com
–2020-11-03 17:56:58– http://baidu.com/
正在解析主机 baidu.com (baidu.com)… 失败:未知的名称或服务。
wget: 无法解析主机地址 “baidu.com”

[root@offline-200 services]# ping 192.168.2.3
PING 192.168.2.3 (192.168.2.3) 56(84) bytes of data.
64 bytes from 192.168.2.3: icmp_seq=1 ttl=128 time=0.305 ms
64 bytes from 192.168.2.3: icmp_seq=2 ttl=128 time=0.245 ms
64 bytes from 192.168.2.3: icmp_seq=3 ttl=128 time=0.211 ms
64 bytes from 192.168.2.3: icmp_seq=4 ttl=128 time=0.255 ms
64 bytes from 192.168.2.3: icmp_seq=5 ttl=128 time=0.353 ms
— 192.168.2.3 ping statistics —
5 packets transmitted, 5 received, 0% packet loss, time 3999ms
rtt min/avg/max/mdev = 0.211/0.273/0.353/0.053 ms
[root@offline-200 services]# ping 192.168.2.1
PING 192.168.2.1 (192.168.2.1) 56(84) bytes of data.
64 bytes from 192.168.2.1: icmp_seq=1 ttl=255 time=1.39 ms
64 bytes from 192.168.2.1: icmp_seq=2 ttl=255 time=1.47 ms
64 bytes from 192.168.2.1: icmp_seq=3 ttl=255 time=1.43 ms
— 192.168.2.1 ping statistics —
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 1.393/1.433/1.470/0.031 ms

首先,检查DNS服务器是否设置且是否设置正确。


cat  resolv.conf

如下所示,DNS只是一个局域网的服务器。具体之前为什么这么设置,现在也搞不清楚。

[root@offline-200 services]# cat /etc/resolv.conf
Generated by NetworkManager
search host.com
nameserver 192.168.2.200

不管之前是什么原因,现在使用vi进行编辑新加两个DNS服务器。

cat /etc/resolv.conf

#阿里DNS服务器

nameserver 223.5.5.5

nameserver 223.6.6.6

[root@offline-200 services]# vi /etc/resolv.conf
[root@offline-200 services]# cat /etc/resolv.conf
Generated by NetworkManager
search host.com
nameserver 192.168.2.200
nameserver 223.5.5.5
nameserver 223.6.6.6

新加DNS服务器之后保存,测试访问外网通过。

curl  www.baidu.com

转载请注明:清风博客 » Linux无法访问外网问题

]]>
https://www.skyfinder.cc/2020/11/16/linux-net-work/feed/ 0
.NET混淆加壳代码保护工具.NET Reactor最新版 https://www.skyfinder.cc/2020/11/10/netreactor/ https://www.skyfinder.cc/2020/11/10/netreactor/#respond Tue, 10 Nov 2020 14:52:29 +0000 https://www.skyfinder.cc/?p=3255

.NET Reactor是一款功能强大的代码保护以及许可授权管理系统软件,主要用于开发人员保护其.NET软件程序,.NET Reactor支持所有支持.NET编译的程序开发语言。.

.net Reactor功能介绍

.net Reactor设置说明

下载

.NET.Reactor 6.3 提取码:k5wr
压缩文件设置了解压密码:www.skyfinder.cc

转载请注明:清风博客 » .NET混淆加壳代码保护工具.NET Reactor最新版

]]>
https://www.skyfinder.cc/2020/11/10/netreactor/feed/ 0
.NET 使用MySql 8.0报caching_sha2_password错误的问题处理 https://www.skyfinder.cc/2020/10/05/net-mysql-caching_sha2_password-error/ https://www.skyfinder.cc/2020/10/05/net-mysql-caching_sha2_password-error/#respond Mon, 05 Oct 2020 13:41:04 +0000 https://www.skyfinder.cc/?p=3224 背景

接手别人项目进行维护,使用Mysql 8.0 数据库正确还原,但是项目却无法启动,经过调试发现以下问题。

MySqlException Authentication method ‘caching_sha2_password’ not supported by any of the available plugins。

通常的报这个错误是因为它的身份验证方式是 mysql_native_password ,不是caching_sha2_password导致。

Mysql 官方相关资料:https://dev.mysql.com/doc/refman/8.0/en/caching-sha2-pluggable-authentication.html

解决方法

首先找到MySql 8.0 的安装目录,看一下是否存在my.ini配置文件,默认安装路径如下:

C:\Program Files\MySQL\MySQL Server 8.0

现在并没有发现my.ini配置文件,经过了解Mysql 8.0 安装后会将配置相关内容保存在以下目录中:

C:\ProgramData\MySQL\MySQL Server 8.0

打开my.ini配置文件并找到caching_sha2_password所在的行。

default_authentication_plugin=caching_sha2_password替换为default_authentication_plugin=mysql_native_password

操作完成后保存,然后重启mysql 8.0服务即可。

转载请注明:清风博客 » .NET 使用MySql 8.0报caching_sha2_password错误的问题处理

]]>
https://www.skyfinder.cc/2020/10/05/net-mysql-caching_sha2_password-error/feed/ 0
NET CORE将对象属性按照指定顺序输出 https://www.skyfinder.cc/2020/09/08/net-core-object-attribute-sort-order/ https://www.skyfinder.cc/2020/09/08/net-core-object-attribute-sort-order/#respond Tue, 08 Sep 2020 08:42:31 +0000 https://www.skyfinder.cc/?p=3194 背景

因业务需求,需要与第三方进行融合登录。第三方融合登录接口有关于验签的要求,将解密的数据按照规定的顺序进行MD5进行签名验证并与提供的MD5签名作为对比。其加密的明文是Json字符串,解密后还原后要按照URl参数的形式进行排列进行MD5签名。

规定

加密参数(注:加密参数名称均为小写字母,没有使用驼峰法命名)

名称类型默认值简介
sourceidString必传来源标识
targetidString必传目标标识
usercodeString必传用户唯一标识
usernameString用户姓名
idcardString身份证号码
phoneString手机号码
ounameString部门名称
timeString必传当前时间戳,精确到毫秒

签名数据采用以上面表格顺序以及以下格式进行字段拼接

sourceid=skyfinder&targetid=sky&usercode=100001&username=清风&idcard=110101199003074194&phone=16620927111&ouname=博客&time=1599539358

实现

创建一个自定义特性SortOrderAttribute,用来标识实体属性顺序与名称。


public class SortOrderAttribute: Attribute
 {
        public string Name { get; set; }

        public int Index { get; set; }

        public SortOrderAttribute(string name,int index)
        {
            Name = name;
            Index = index;
        }
    }

根据表格内容创建实体模型指定其排列顺序并通过方法GetUrIParameterString实现顺序输出内容。


public class PoliceStudiesUser
{
        /// <summary>
        /// 来源标识
        /// </summary>
        [SortOrder("来源标识",1)]
        public string sourceid { get; set; }
        /// <summary>
        /// 目标标识
        /// </summary>
        [SortOrder("来源标识", 2)]
        public string targetid { get; set; }
        /// <summary>
        /// 用户唯一标识
        /// </summary>
        [SortOrder("来源标识", 3)]
        public string usercode { get; set; }
        /// <summary>
        /// 用户姓名
        /// </summary>
        [SortOrder("来源标识", 4)]
        public string username { get; set; }
        /// <summary>
        /// 身份证号码
        /// </summary>
        [SortOrder("来源标识", 5)]
        public string idcard { get; set; }
        /// <summary>
        /// 手机号码
        /// </summary>
        [SortOrder("来源标识", 6)]
        public string phone { get; set; }
        /// <summary>
        /// 部门名称
        /// </summary>
        [SortOrder("来源标识", 7)]
        public string ouname { get; set; }

        /// <summary>
        /// 当前时间戳,精确到毫秒
        /// </summary>
        [SortOrder("来源标识", 8)]
        public string time { get; set; }

        public string GetUrIParameterString()
        {
            List<string> urlParameter = new List<string>();
            //foreach (PropertyInfo item in this.GetType().GetProperties().OrderBy(p => (p.GetCustomAttributes(true)[0] as SortOrderAttribute).Index).ToArray())
            Type type = this.GetType();
            var properties = type.GetProperties().OrderBy(p => (p.GetCustomAttributes(true)[0] as SortOrderAttribute).Index).ToArray();
            foreach (var item in properties)
            {
                string value = item.GetValue(this, null) == null ? "" : item.GetValue(this, null).ToString().Trim();
                if (string.IsNullOrWhiteSpace(value))
                {
                    continue;
                }
                urlParameter.Add($"{item.Name}={value}");
            }
            return string.Join("&",urlParameter);
        }
    }

调用测试

       

 static void Main(string[] args)
 {
            PoliceStudiesUser studiesUser = new PoliceStudiesUser() {
                sourceid="skyfinder",
                targetid="sky",
                idcard= "110101199003074194",
                usercode="100001",
                username="清风",
                ouname="博客",
                phone= "16620927111",
                time= "1599539358"
            };
            Console.WriteLine(studiesUser.GetUrIParameterString());
            Console.Read();
 }

示例下载

NET CORE指定顺序输出对象属性内容

转载请注明:清风博客 » NET CORE将对象属性按照指定顺序输出

]]>
https://www.skyfinder.cc/2020/09/08/net-core-object-attribute-sort-order/feed/ 0
推送Docker镜像被拒绝问题处理 https://www.skyfinder.cc/2020/09/04/docker-push-denied/ https://www.skyfinder.cc/2020/09/04/docker-push-denied/#respond Thu, 03 Sep 2020 16:00:00 +0000 https://www.skyfinder.cc/?p=3178 构建了自己常用的基础镜像,就打算推送到Docker Hub上。首先使用docker login 进行登录,然后就使用docker push 执行镜像推送,最后返回错误信息如下:

denied: requested access to the resource is denied

如下图:

在网上找了下相关信息,大部分都是说认证、登录等信息,按照相关信息试一试也没有什么用。最后发现是镜像名称不符合Docker规范,从而导致了镜像推送被拒绝。

推送的镜像命名规范如下:

登录名/镜像名称:标签

例如:

skyfinder/microsoft-dotnet-2.1-aspnetcore-runtime-libgdiplus:latest

如果现有的镜像名称不符合规范,可以使用tag打一个标签,如下:

docker tag skyfinder/microsoft/dotnet-2.1-aspnetcore-runtime-libgdiplus:1.0 skyfinder/microsoft-dotnet-2.1-aspnetcore-runtime-libgdiplus:latest

当镜像名称符合规范后,就可以使用docker push 来完成推送,如下:

docker push skyfinder/microsoft-dotnet-2.1-aspnetcore-runtime-libgdiplus:latest

至此也不会再有关于文章开头所描述的错误。

转载请注明:清风博客 » 推送Docker镜像被拒绝问题处理

]]>
https://www.skyfinder.cc/2020/09/04/docker-push-denied/feed/ 0
.NET CORE实现MD5加密 https://www.skyfinder.cc/2020/09/03/net-core-md5/ https://www.skyfinder.cc/2020/09/03/net-core-md5/#respond Wed, 02 Sep 2020 16:00:00 +0000 https://www.skyfinder.cc/?p=3154 背景

因某些需求,需要与合作单位进行相应的数据交互,而交互均使用了加密方式处理并用MD5作为签名,以便校验传输内容是否遭到篡改。

MD5

md5是一种信息摘要算法,它可以从一个字符串或一个文件中按照一定的规则生成一个特殊的字符串,并且一个文件所对应的MD5摘要是固定的,当文件内容变化后,其MD5值也会不一样,因此,在应用中经常使用MD5值来验证一段数据有没有被篡改。

.NET CORE 实现MD5

以下简单实现,支持返回大小写、32位以及16位MD5字符串。


    public static class EncryptionMd5
    {
         /// <summary>
        /// md5加密
        /// </summary>
        /// <param name="content">要加密的内容</param>
        /// <param name="isUpper">是否大写,默认小写</param>
        /// <param name="is16">是否是16位,默认32位</param>
        /// <returns></returns>
        public static string Md5(string content,bool isUpper=false,bool is16=false)
        {
            using (var md5 = MD5.Create())
            {
                var result = md5.ComputeHash(Encoding.UTF8.GetBytes(content));
                string md5Str = BitConverter.ToString(result);
                md5Str = md5Str.Replace("-", "");
                md5Str= isUpper ? md5Str : md5Str.ToLower();
                return is16 ? md5Str.Substring(8,16) : md5Str;
            }
        }
    }
以上是使用.NET CORE自身提供的MD5加密进行实现,如果想了解原理以及具体实现方式,请使用万能搜索引擎查找。

使用方式


using System;
using System.Text;
using System.Security.Cryptography;
namespace CryptographyApplication
{
   class SecurityCryptography
   {
      static void Main(string[] args)
      {
         Console.WriteLine(EncryptionMd5.Md5("Hello World!"));
         Console.ReadKey();
      }
   }
}

转载请注明:清风博客 » .NET CORE实现MD5加密

]]>
https://www.skyfinder.cc/2020/09/03/net-core-md5/feed/ 0
.Net Core实现AES加解密 https://www.skyfinder.cc/2020/09/02/net-core-encryption-aes/ https://www.skyfinder.cc/2020/09/02/net-core-encryption-aes/#respond Wed, 02 Sep 2020 04:30:29 +0000 https://www.skyfinder.cc/?p=3148 背景

因业务需求,需要与其他平台实现融合登录,根据提供融合登录方的文档内容,对AES加密解密相关内容使用.NET CORE来进行一次实现。以下记录实现AES加解密后的内容,便以后备用。

AES

高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。严格地说,AESRijndael加密法并不完全一样(虽然在实际应用中二者可以互换),因为Rijndael加密法可以支持更大范围的区块和密钥长度:AES的区块长度固定为128 比特,密钥长度则可以是128192256比特;而Rijndael使用的密钥和区块长度可以是32位的整数倍,以128位为下限,256比特为上限。包括AES-ECBAES-CBCAES-CTRAES-OFBAES-CFB

.NET CORE 的AES加解密实现


    public enum CiphertextType
    {
        /// <summary>
        /// Base64
        /// </summary>
        Base64 = 1,
        /// <summary>
        /// 16进制字符串
        /// </summary>
        Hex = 2
    }
    public static class EncryptionAes
    {
        #region AES加密

        /// <summary>
        /// AES加密
        /// </summary>
        /// <param name="source"></param>
        /// <param name="key">密钥</param>
        /// <param name="iv">初始向量</param>
        /// <param name="padding">填充模式</param>
        /// <param name="mode">加密模式</param>
        /// <param name="ciphertextType">密文类型</param>
        /// <returns></returns>
        public static (bool isSuccess, string text) AESEncrypt(this string source, string key, string iv = "", PaddingMode padding = PaddingMode.PKCS7, CipherMode mode = CipherMode.CBC, CiphertextType ciphertextType = CiphertextType.Base64)
        {
            try
            {
                byte[] keyBytes = Encoding.UTF8.GetBytes(key);
                byte[] textBytes = Encoding.UTF8.GetBytes(source);
                byte[] ivBytes = Encoding.UTF8.GetBytes(iv);

                byte[] useKeyBytes = new byte[16];
                byte[] useIvBytes = new byte[16];

                if (keyBytes.Length > useKeyBytes.Length)
                {
                    Array.Copy(keyBytes, useKeyBytes, useKeyBytes.Length);
                }
                else
                {
                    Array.Copy(keyBytes, useKeyBytes, keyBytes.Length);
                }
                if (ivBytes.Length > useIvBytes.Length)
                {
                    Array.Copy(ivBytes, useIvBytes, useIvBytes.Length);
                }
                else
                {
                    Array.Copy(ivBytes, useIvBytes, ivBytes.Length);
                }

                Aes aes = System.Security.Cryptography.Aes.Create();
                aes.KeySize = 256;//秘钥的大小,以位为单位,128,256等
                aes.BlockSize = 128;//支持的块大小
                aes.Padding = padding;//填充模式
                aes.Mode = mode;
                aes.Key = useKeyBytes;
                aes.IV = useIvBytes;//初始化向量,如果没有设置默认的16个0

                ICryptoTransform cryptoTransform = aes.CreateEncryptor();
                byte[] resultBytes = cryptoTransform.TransformFinalBlock(textBytes, 0, textBytes.Length);
                return (true, CipherByteArrayToString(resultBytes, ciphertextType));
            }
            catch (Exception ex)
            {
                return (false, ex.Message);
            }
        }

        #endregion



        #region AES解密

        /// <summary>
        /// AES解密
        /// </summary>
        /// <param name="source"></param>
        /// <param name="key">密钥</param>
        /// <param name="iv">初始向量</param>
        /// <param name="padding">填充模式</param>
        /// <param name="mode">加密模式</param>
        /// <param name="ciphertextType">密文类型</param>
        /// <returns></returns>
        public static (bool isSuccess, string text) AESDecrypt(this string source, string key, string iv = "", PaddingMode padding = PaddingMode.PKCS7, CipherMode mode = CipherMode.CBC, CiphertextType ciphertextType = CiphertextType.Base64)
        {
            try
            {
                byte[] keyBytes = Encoding.UTF8.GetBytes(key);
                byte[] textBytes = CiphertextStringToByteArray(source, ciphertextType);
                byte[] ivBytes = Encoding.UTF8.GetBytes(iv);

                byte[] useKeyBytes = new byte[16];
                byte[] useIvBytes = new byte[16];

                if (keyBytes.Length > useKeyBytes.Length)
                {
                    Array.Copy(keyBytes, useKeyBytes, useKeyBytes.Length);
                }
                else
                {
                    Array.Copy(keyBytes, useKeyBytes, keyBytes.Length);
                }

                if (ivBytes.Length > useIvBytes.Length)
                {
                    Array.Copy(ivBytes, useIvBytes, useIvBytes.Length);
                }
                else
                {
                    Array.Copy(ivBytes, useIvBytes, ivBytes.Length);
                }

                Aes aes = System.Security.Cryptography.Aes.Create();
                aes.KeySize = 256;//秘钥的大小,以位为单位,128,256等
                aes.BlockSize = 128;//支持的块大小
                aes.Padding = padding;//填充模式
                aes.Mode = mode;
                aes.Key = useKeyBytes;
                aes.IV = useIvBytes;//初始化向量,如果没有设置默认的16个0

                ICryptoTransform decryptoTransform = aes.CreateDecryptor();
                byte[] resultBytes = decryptoTransform.TransformFinalBlock(textBytes, 0, textBytes.Length);
                return (true, Encoding.UTF8.GetString(resultBytes));
            }
            catch (Exception ex)
            {
                return (false, ex.Message);
            }
        }

        /// <summary>
        /// 通过密文返回加密byte数组
        /// </summary>
        /// <param name="ciphertext"></param>
        /// <param name="ciphertextType"></param>
        /// <returns></returns>
        public static byte[] CiphertextStringToByteArray(string ciphertext, CiphertextType ciphertextType)
        {
            byte[] cipherByte;
            switch (ciphertextType)
            {
                case CiphertextType.Base64:
                    cipherByte = Convert.FromBase64String(ciphertext);
                    break;
                case CiphertextType.Hex:
                    cipherByte = HexStringToByteArray(ciphertext);
                    break;
                default:
                    cipherByte = Convert.FromBase64String(ciphertext);
                    break;
            }
            return cipherByte;
        }

        /// <summary>
        /// 通过加密的Byte数组返回加密后的密文
        /// </summary>
        /// <param name="cipherByte"></param>
        /// <param name="ciphertextType"></param>
        /// <returns></returns>
        public static string CipherByteArrayToString(byte[] cipherByte, CiphertextType ciphertextType)
        {
            string ciphertext = "";
            switch (ciphertextType)
            {
                case CiphertextType.Base64:
                    ciphertext = Convert.ToBase64String(cipherByte);
                    break;
                case CiphertextType.Hex:
                    ciphertext = ByteArrayToHexString(cipherByte);
                    break;
                default:
                    ciphertext = Convert.ToBase64String(cipherByte);
                    break;
            }
            return ciphertext;
        }

        /// <summary>
        /// Hex字符串转Byte
        /// </summary>
        /// <param name="hexContent"></param>
        /// <returns></returns>
        public static byte[] HexStringToByteArray(string hexContent)
        {
            hexContent = hexContent.Replace(" ", "");
            byte[] buffer = new byte[hexContent.Length / 2];
            for (int i = 0; i < hexContent.Length; i += 2)
            {
                buffer[i / 2] = (byte)Convert.ToByte(hexContent.Substring(i, 2), 16);
            }
            return buffer;
        }
        /// <summary>
        /// Byte转Hex字符串
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static string ByteArrayToHexString(byte[] data)
        {
            StringBuilder sb = new StringBuilder(data.Length * 3);
            foreach (byte b in data)
            {
                sb.Append(Convert.ToString(b, 16).PadLeft(2, '0'));
            }
            return sb.ToString().ToUpper();
        }
        #endregion
    }

调用AES加解密


    class Program
    {
        static void Main(string[] args)
        {
            var ddd = "111111111" .AESEncrypt("3EDsw9[A4W5FdS{]3W","0102030504030201", PaddingMode.PKCS7);
            Console.WriteLine($"加密:{ddd.text}");
            Console.WriteLine($"解密:{(ddd.text.AESDecrypt("3EDsw9[A4W5FdS{]3W", "0102030504030201", PaddingMode.PKCS7)).text}");
            Console.Read();
        }
    }

示例下载

.Net Core实现AES加解密示例

转载请注明:清风博客 » .Net Core实现AES加解密

]]>
https://www.skyfinder.cc/2020/09/02/net-core-encryption-aes/feed/ 0
Java实现AES加解密 https://www.skyfinder.cc/2020/09/01/java-aes-encryption/ https://www.skyfinder.cc/2020/09/01/java-aes-encryption/#respond Tue, 01 Sep 2020 06:46:16 +0000 https://www.skyfinder.cc/?p=3140 因业务需求,需要进行融合登录,根据提供融合登录方的文档内容,对AES加密解密相关内容使用.NET CORE来进行一次实现。使用.NET CORE完成后,根据文档提到的密文进行解密,很遗憾解密无法完成。最终根据提供的Java文件进行相关确认,发现文档中所表述内容与Java示例文件中出现诸多不一致的地方。最后经过咨询并确认了以Java示例文件中的内容为准,所以此处记录一下这个AES加密解密的方法。


import java.security.Key;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

/**
 * AES加密工具类
 * 
 */
public class AESCommonUtils
{

    /** 16位向量 双方约定一致 */
    private static final String IV = "0102030504030201";

    /** 密钥 双方约定一致 */
    private static final String KEY = "3EDsw9[A4W5FdS{]3W";

    /** 加密模式及填充方式 */
    private static final String MODE_PADDING = "AES/CBC/NoPadding";

    /** 加密模式 */
    private static final String MODE = "AES";

    /** 编码格式 UTF-8 */
    private static final String CHARSET_UTF8 = "UTF-8";

    /**
     * AES加密过程
     * 
     * @param strKey
     * @return
     * @throws Exception
     */
    public static String encrypt(String strKey, String info) throws Exception {
        SecretKeySpec skeySpec = getKey(strKey);
        Cipher cipher = Cipher.getInstance(MODE_PADDING);
        int blockSize = cipher.getBlockSize();

        byte[] dataBytes = info.getBytes(CHARSET_UTF8);
        int plaintextLength = dataBytes.length;
        if (plaintextLength % blockSize != 0) {
            plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize));
        }

        byte[] plaintext = new byte[plaintextLength];
        System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);
        IvParameterSpec iv = new IvParameterSpec(IV.getBytes());
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
        byte[] encrypted = cipher.doFinal(plaintext);

        // return new BASE64Encoder().encode(encrypted);
        return byte2hex(encrypted);
    }

    /***
     * AES解密
     * 
     * @param strKey
     * @param strIn
     * @return
     * @throws Exception
     */
    public static String decrypt(String strKey, String info) throws Exception {
        try {
            byte[] byteResult = decrypt2Byte(strKey, info);
            String result = new String(byteResult, CHARSET_UTF8);
            return result;
        }
        catch (Exception e) {
            return info;
        }

    }

    /***
     * AES解密详细过程
     * 
     * @param strKey
     * @param content
     * @return
     * @throws Exception
     */
    private static byte[] decrypt2Byte(String strKey, String content) throws Exception {
        SecretKeySpec skeySpec = getKey(strKey);

        Cipher cipher = Cipher.getInstance(MODE_PADDING);
        IvParameterSpec iv = new IvParameterSpec(IV.getBytes());
        cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
        // byte[] encrypted = Base64.decode(content)
        byte[] encrypted = hex2byte(content);
        byte[] original = flushZeroElements(cipher.doFinal(encrypted));

        return original;

    }

    /**
     * 清除AES加密前补位的内容
     * 
     * @param source
     * @return
     */
    private static byte[] flushZeroElements(byte[] source) {
        int i = 0;
        for (byte b : source) {
            if (b == 0) {
                break;
            }
            i++;
        }
        byte[] result = Arrays.copyOf(source, i);
        return result;
    }

    /***
     * 针对长度不满16的密钥进行补0操作
     * 
     * @param strKey
     * @return
     * @throws Exception
     */
    private static SecretKeySpec getKey(String strKey) throws Exception {
        byte[] arrBTmp = strKey.getBytes();
        byte[] arrB = new byte[16]; // 创建一个空的16位字节数组(默认值为0)

        for (int i = 0; i < arrBTmp.length && i < arrB.length; i++) {
            arrB[i] = arrBTmp[i];
        }

        SecretKeySpec skeySpec = new SecretKeySpec(arrB, MODE);

        return skeySpec;
    }

    /***
     * 把16进制转成byte类型数组
     * 
     * @param strhex
     * @return
     */
    public static byte[] hex2byte(String strhex) {
        if (strhex == null) {
            return null;
        }
        int l = strhex.length();
        if (l % 2 == 1) {
            return null;
        }
        byte[] b = new byte[l / 2];
        for (int i = 0; i != l / 2; i++) {
            b[i] = (byte) Integer.parseInt(strhex.substring(i * 2, i * 2 + 2), 16);
        }
        return b;
    }

    /**
     * 把byte数组转成16进制
     * 
     * @param b
     * @return
     */
    public static String byte2hex(byte[] b) {
        String hs = "";
        String stmp = "";
        for (int n = 0; n < b.length; n++) {
            stmp = (Integer.toHexString(b[n] & 0XFF));
            if (stmp.length() == 1) {
                hs = hs + "0" + stmp;
            }
            else {
                hs = hs + stmp;
            }
        }
        return hs.toUpperCase();
    }

    public static void main(String[] args) {
        String userInfo = "11111";
        try {
                        userInfo = AESCommonUtils.encrypt(KEY,userInfo);
                        System.out.println("加密后:***" + userInfo + "===========");

                        userInfo= AESCommonUtils.decrypt(KEY,userInfo);
                        System.out.println("解密后***" + userInfo + "===========");
           
        }
        catch (Exception e) {
            System.out.println("加解密异常 : " + e.toString());
        }
    }

}

转载请注明:清风博客 » Java实现AES加解密

]]>
https://www.skyfinder.cc/2020/09/01/java-aes-encryption/feed/ 0
CodeSmith 7系列安装 https://www.skyfinder.cc/2020/08/23/codesmith-7-install/ https://www.skyfinder.cc/2020/08/23/codesmith-7-install/#respond Sun, 23 Aug 2020 01:00:00 +0000 https://www.skyfinder.cc/?p=3094

CodeSmith

CodeSmith 是一种语法类似于ASP.NET的基于模板的代码生成器,程序可以自定义模板,作为开发人员工具,它可以减少重复编码的劳动量,提高效率。

CodeSmith 是一种基于模板的代码生成工具,它使用类似于ASP.NET的语法来生成任意类型的代码或文本。与其他许多代码生成工具不同,CodeSmith 不要求您订阅特定的应用程序设计或体系结构。使用 CodeSmith,可以生成包括简单的强类型集合和完整应用程序在内的任何东西。

CodeSmith 7 下载

CodeSmith 提取码:3pv6
压缩文件设置了解压密码:www.skyfinder.cc

CodeSmith 7安装

双击进行安装,点击next(下一步),以后的每一步都点击next进行下一步,直到点击Finish安装完成。

点击Finish后会出现以下界面,暂时不要输入任何内容且不要关闭窗体。如果真的关闭了,也没有什么关系,需要的时候再打开即可。

CodeSmith 7注册

打开KeyGenerator文件夹下的CodesmithKeyGenerator.exe工具,如下图所示:

打开激活工具后,在Prefix里面输入:CS70P-,因为使用的是CodeSmith 7.0.2,所以是CS70P-,如果是8.0则是CS80P-。其他的保持默认,点击Generate按钮。

下图则是点击Generate后计算出的假的注册码。复制假的注册码且注册工具不要关闭

回到CodeSmith Generator 程序界面,如果之前已经关闭就重新启动你的CodeSmith,输入上面复制的假的注册码并点击Register

输入名字和组织,其中Serial Number是我们上一步输入的内容,如果上一步没有输入任何内容,此处就需要粘贴之前注册机复制的假注册码。点击Register

点击按钮Activate by Entering a Code

记下机器码(Machine Code)且窗体不要关闭,如果嫌手动记录麻烦就使用下一步方法临时保存。

点击左侧按钮Copy to Clipboard 按钮并将复制的内容粘贴到文本临时保存。如果上一步已经手动记录且保证无误,此步骤可以省略。

回到注册工具界面并点击Generate Activation按钮

替换Prefix以后内容为CS70P-,修改时间且远大于当前时间。

将之前保存的Machine Code(机器码) ,粘贴到Machine Hash Code 下的文本框内并点击Generate来生成最终的激活码。

点击Generate后,在Activation下的文本框内就生成了最后的激活码

将激活码复制下来,回到CodeSmith的激活码待输入界面,在Activation Code下的文本框内中粘贴刚才复制的激活码,点击Activate来完成激活。

出现以下内容等待完成。

进度完成后就可以进入应用了,看下是否完成激活即可。

转载请注明:清风博客 » CodeSmith 7系列安装

]]>
https://www.skyfinder.cc/2020/08/23/codesmith-7-install/feed/ 0
Adobe Photoshop https://www.skyfinder.cc/2020/08/22/adobe-photoshop/ https://www.skyfinder.cc/2020/08/22/adobe-photoshop/#respond Fri, 21 Aug 2020 22:00:00 +0000 https://www.skyfinder.cc/?p=3087

Adobe Photoshop介绍

Adobe Photoshop,简称“PS”,是由Adobe Systems开发和发行的图像处理软件。

Photoshop主要处理以像素所构成的数字图像。使用其众多的编修与绘图工具,可以有效地进行图片编辑工作。ps有很多功能,在图像、图形、文字、视频、出版等各方面都有涉及。

功能上看可分为图像编辑、图像合成、校色调色及功能色效制作部分等。 图像编辑是图像处理的基础,可以对图像做各种变换如放大、缩小、旋转、倾斜、镜像、透视等;也可进行复制、去除斑点、修补、修饰图像的残损等。

图像合成则是将几幅图像通过图层操作、工具应用合成完整的、传达明确意义的图像,这是美术设计的必经之路;该软件提供的绘图工具让外来图像与创意很好地融合。校色调色可方便快捷地对图像的颜色进行明暗、色偏的调整和校正,也可在不同颜色进行切换以满足图像在不同领域如网页设计、印刷、多媒体等方面应用。

特效制作在该软件中主要由滤镜、通道及工具综合应用完成。包括图像的特效创意和特效字的制作,如油画、浮雕、石膏画、素描等常用的传统美术技巧都可藉由该软件特效完成。

Adobe Photoshop下载

Adobe Photoshop CC 2019

Adobe Photoshop CC 2019 提取码:v8nw

转载请注明:清风博客 » Adobe Photoshop

]]>
https://www.skyfinder.cc/2020/08/22/adobe-photoshop/feed/ 0
adobe photoshop cc 2019打开图片显示空白图层的问题 https://www.skyfinder.cc/2020/08/16/adobe-photoshop-cc-2019-not-displayed/ https://www.skyfinder.cc/2020/08/16/adobe-photoshop-cc-2019-not-displayed/#respond Sun, 16 Aug 2020 04:21:20 +0000 https://www.skyfinder.cc/?p=3074 卸载了已经使用很久的Photoshop CS 6,重新安装一个稍微高版本adobe photoshop cc 2019,安装完成后使用photoshop打开图片显示空白图层,可能是与系统硬件不兼容。

  • 首先选择编辑菜单
  • 再选择首选项菜单
  • 然后选择性能菜单
  • 在图形处理器设置区域取消勾选使用图形处理器
  • 点击确定完成设置
  • 重新打开图片即刻正常显示

转载请注明:清风博客 » adobe photoshop cc 2019打开图片显示空白图层的问题

]]>
https://www.skyfinder.cc/2020/08/16/adobe-photoshop-cc-2019-not-displayed/feed/ 0
Windows 10 安装Apache https://www.skyfinder.cc/2020/08/14/windows10installapacheserver/ https://www.skyfinder.cc/2020/08/14/windows10installapacheserver/#respond Fri, 14 Aug 2020 02:39:06 +0000 https://www.skyfinder.cc/?p=3046

HTTP服务器Apache

Apache HTTP Server Project是一项协作软件开发工作,旨在创建HTTP(Web)服务器的健壮,商业级,功能强大且可免费使用的源代码实现。该项目由世界各地的一组志愿者共同管理,使用Internet和Web进行通信,计划和开发服务器及其相关文档。该项目是Apache Software Foundation的一部分。另外,成百上千的用户为该项目贡献了想法,代码和文档。

Apache HTTP Server 下载

打开Apache HTTP Server官网:http://httpd.apache.org

点击Download

点击Files for Microsoft Windows链接

点击ApacheHaus

点击下载完成。

Apache HTTP Server 安装

将下载完成的安装包移到将要安装的目录并解压。

例如:将解压后的文件夹移动到目录D:\Program Files\httpd

Apache HTTP Server 配置

 打开httpd.conf文件。例如:D:\Program Files\httpd\Apache24\conf\httpd.conf

修改Apache实际绝对安装目录Define SRVROOT。其中D:/Program Files/httpd/Apache24就是实际的安装目录。如果本机80端口被占用,就需要更改默认端口Listen,因为本机端口被占用,所以改为8098作为新端口。

检查配置文件是否合法,打开cmd切换目录到D:\Program Files\httpd\Apache24\bin下,输入一下命令并执行


httpd -t

安装Apache的主服务,以管理员身份打开cmd并切换目录到D:\Program Files\httpd\Apache24\bin,输入以下命令进行执行安装:


httpd -k install -n Apache

安装成功如上图所示,其中-n后面参数是自定义Windows服务名称,例如:Apache

Apache服务器的启动

Windows下Apache服务器的启动方式有以下几种

利用WIndows服务管理启动。

同时按下win+r键,在运行窗口中输入services.msc,即可打开服务

利用命令行启动

Windows系统自带命令


net start Apache

Apache HTTP Server 自带命令

httpd -k start

利用Apache服务器自身的视窗打开

打开目录D:\Program Files\httpd\Apache24\bin并打开ApacheMonitor.exe

打开浏览器,输入访问http://localhost:8098,若出现如下图所示界面,则Apache服务器的基本配置完毕,此时apache服务器已经可以运行。 

Apache HTTP Server 卸载

如果不在需要使用Apache HTTP Server,可以删除服务再删除文件夹。以管理员身份打开cmd,并切换目录到D:\Program Files\httpd\Apache24\bin,执行以下命令


httpd -k stop
httpd -k uninstall

或者使用Windows系统自带的命令sc delete 服务名进行删除


sc delete Apache

结束

Apache HTTP Server的下载、安装、启动以及卸载就全部结束。

转载请注明:清风博客 » Windows 10 安装Apache

]]>
https://www.skyfinder.cc/2020/08/14/windows10installapacheserver/feed/ 0
asp .net core 不使用构造函数获得注入的对象 https://www.skyfinder.cc/2020/08/08/aspnetcorediget/ https://www.skyfinder.cc/2020/08/08/aspnetcorediget/#comments Sat, 08 Aug 2020 01:00:00 +0000 https://www.skyfinder.cc/?p=3026 使用asp .net core 2.1使用自带的依赖注入,自带的依赖注入是构造函数注入。有些情况,构造函数注入并不能满足需求,所以需要使用其他方法获取指定实例。

    
public interface IEngine
 {
        /// <summary>
        /// 类型构建
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        object Resolve(Type type);
}
    
public class GetEngine: IEngine
{
        private IServiceProvider _serviceProvider;
        public GetEngine(IServiceProvider serviceProvider)
        {
            this._serviceProvider = serviceProvider;
        }

        /// <summary>
        /// 类型构建
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public object Resolve(Type type)
        {
            return _serviceProvider.GetService(type);
        }
}

public class EnginContext
 {
        private static IEngine _engine;

        [MethodImpl(MethodImplOptions.Synchronized)]
        public static IEngine Initialize(IEngine engine)
        {
            if (_engine == null)
                _engine = engine;
            return _engine;
        }

        public static IEngine Current
        {
            get
            {
                return _engine;
            }
        }
 }

需要在 Startup.csConfigure方法中调用,如下:


EnginContext.Initialize(new GetEngine(app.ApplicationServices));

完整示例如下:


public void Configure(IApplicationBuilder app, IHostingEnvironment env)
 {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
                app.UseHsts();
            }

            EnginContext.Initialize(new GetEngine(app.ApplicationServices));

            app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseCookiePolicy();
            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
  }

新增一个类Information进行测试,如下:


    public class Information
    {
        private string Name => "Dot Net Core";
        public string GetName()
        {
            return $"你好!{Name}";
        }
    }

ConfigureServices方法中将新增的类进行注入。


        
        public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });

            services.AddTransient<Information>();
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
        }

通过以下方式进行获取已经注入的对象。


EnginContext.Current.Resolve(typeof(Information));

使用示例如下:


        public IActionResult About()
        {
            ViewData["Message"] = "Your application description page.";
            var info= EnginContext.Current.Resolve(typeof(Information)) as Information;
            ViewData["Message"] = info.GetName();
            return View();
        }

示例下载

示例

转载请注明:清风博客 » asp .net core 不使用构造函数获得注入的对象

]]>
https://www.skyfinder.cc/2020/08/08/aspnetcorediget/feed/ 2
Docker容器使用gzip压缩保存/加载镜像 https://www.skyfinder.cc/2020/07/16/dockergzipsaveload/ https://www.skyfinder.cc/2020/07/16/dockergzipsaveload/#respond Thu, 16 Jul 2020 10:51:08 +0000 https://www.skyfinder.cc/?p=3009 保存镜像
docker save <myimagename>:<tag> | gzip > <myimagename>_<tag>.tar.gz

加载镜像

gunzip -c <myimagename>_<tag>.tar.gz | docker load

转载请注明:清风博客 » Docker容器使用gzip压缩保存/加载镜像

]]>
https://www.skyfinder.cc/2020/07/16/dockergzipsaveload/feed/ 0
炒面 https://www.skyfinder.cc/2020/07/14/chowmein/ https://www.skyfinder.cc/2020/07/14/chowmein/#respond Mon, 13 Jul 2020 16:42:25 +0000 https://www.skyfinder.cc/?p=2045 说起炒面,它在大多数人的认知中应该是炒面条了吧!尽管这是在大多数人的认知,但在我记忆中却并非如此。

其实,炒面在我记忆中非常简单,它仅仅是炒面粉而已。时间似乎过了很久,但是好像又恍如昨日,而一些事情总是忽远忽近 ,又或者忽隐忽现,让我总是抓不到。我一直在苦苦追寻,也做了无数次的尝试,但再也找不到最初的感觉,也没有曾经的味道。当年疼爱并且为我做炒面的人,如今早已不在。无论现在怎么追寻,始终都是求不得,放不下。 时间真的好像过去很久很久,久到我记不得这件事的具体时间,但可以清晰记得这件事且似乎发生在昨天。 很多时候觉得自己就是病了,病的不轻。无论怎么努力都没有作用,我想大概是真的病了吧!

心中执念,皆是不甘。再次尝试,以此为念。也许,真的应该说声再见!

转载请注明:清风博客 » 炒面

]]>
https://www.skyfinder.cc/2020/07/14/chowmein/feed/ 0
谷歌学术-需要验证您是否来自浙江大学的问题答案 https://www.skyfinder.cc/2020/07/07/googlezhejianguniversity/ https://www.skyfinder.cc/2020/07/07/googlezhejianguniversity/#respond Tue, 07 Jul 2020 06:51:36 +0000 https://www.skyfinder.cc/?p=2971

逛内网论坛的小伙伴们

请问浙江大学内网最大的论坛中, 每天发帖量最大的版块是哪个?(全称, 四个汉字)

答案:心灵之约

浙大本部本科生

请根据以下指引找到并输入三个汉字以验证你是浙大学生(ps:我跟求是潮一点关系都没):Android: 最新版求是潮手机app左边菜单栏中, “其他”一栏的第一个项目是什么(点左上角的选项按钮调出左边栏)(三个汉字,第一个字是”水”)
iOS:最新版求是潮手机app中, 从左往右划动主界面调出左边栏,其中有一栏是三个汉字,图标是一个”水”字,如果你没有自定义它的顺序的话是倒数第三个,它是什么?windows Phone或者老师或者其余无法找到的: 请询问小伙伴 

答案:水朝夕

浙大城院

请问浙江大学内网城市学院端统一密码是什么(即城院内网宽带连接(PPPOE)拨号的密码)?提示: 四个字母@三个数字
(感谢**伦同学提供本问题)如果不知道, 请询问小伙伴 

答案:csxy@123

网址

谷歌学术
警告:本博客不提供任何镜像服务,所谓的谷歌学术验证站点也不是本博提供。使用诸如此类网站会有隐私泄露风险,请谨慎考虑其中风险。

转载请注明:清风博客 » 谷歌学术-需要验证您是否来自浙江大学的问题答案

]]>
https://www.skyfinder.cc/2020/07/07/googlezhejianguniversity/feed/ 0
网页被人恶意嵌入框架(iframe)的处理办法 https://www.skyfinder.cc/2020/06/24/websiteembediframe/ https://www.skyfinder.cc/2020/06/24/websiteembediframe/#respond Wed, 24 Jun 2020 04:00:00 +0000 https://www.skyfinder.cc/?p=2905

背景

人生在世,都会遇到各种问题,就连写个博客也不得安宁。突然发现自己的博客被别人恶意的以框架(iframe/object)形式嵌入了, 这种网页被嵌入框架的情况很常见,只是这次是我罢了。其实我不太明白,为什么要选择个人博客嵌入。不管怎么样自己还是得做出点响应,要不然自己总是觉得缺了一些什么。

发现

这次发现也算一次偶然,突然想看看统计数据,所以就登录到了百度统计查看记录,结果就发现了一些比较奇怪的来源,所以就尝试访问看了看。大致如下:

打开来源后就晓得博客被人恶意嵌入了框架或者被恶意镜像了,经过查看网页代码,确认博客是被恶意嵌入了框架(iframe)。如下图:

观点

这是2008年开始在国内流行另一种流氓行为:使用框架(Frame),将你的网页嵌入它的网页中。只是现在改为了object,其实也是框架了。

其实用框架抓取他人的网页,然后在上面加上自己的广告和站标,这与盗版书商并没有任何不同!

我个人极其讨厌这种行为且反对这种做事方法。

  • 嵌入的真是网址对一般用户是不可见的,欺骗了用户并且侵犯原作者所提供的内容
  • 使用这类框架技术展示别人网站页面视觉效果上完全一样,有着极其高的欺骗性
  • 恶意嵌入者可能在嵌入页面上方附加广告(更严重的是进行木马或者病毒传播),这种行为严重的破坏原作者的形象与意图。
  • 访问者通过框架展示的内容点击链接跳转另外一个链接,其外部的网址是不变的,这种体验效果非常差并且访问者会认为是原作者提供。

点击劫持

点击劫持(ClickJacking)是一种视觉上的欺骗手段。攻击者使用一个透明的iframe,覆盖在一个网页上,然后诱使用户在网页上进行操作,此时用户将在不知情的情况下点击透明的iframe/object页面。通过调整iframe/object页面的位置,可以诱使用户恰好点击在iframe页面的一些功能性按钮上。

应对

前端代码

恶意嵌入网页的人,是不会理会其他人的想法的。为了应对这种恶意的行为,所以就寻求了一种以Javascript脚本代码来防止这种行为继续作恶。将以下代码放入网页源码的头部,即可解决这种恶意行为。


<script type="text/javascript">
// 判断当前的window对象是否是top对象
if (window!=top){ 
    // 如果不是,将top对象的网址自动导向被嵌入网页的网址
	top.location.href =window.location.href; 
}
</script>

其他方式处理

X-Frame-Options HTTP 响应头是用来给浏览器 指示允许一个页面 可否在 <frame><iframe><embed> 或者 <object> 中展现的标记。站点可以通过确保网站没有被嵌入到别人的站点里面,从而避免 clickjacking 攻击

语法

X-Frame-Options 有三个可能的值:


X-Frame-Options: deny
X-Frame-Options: sameorigin
X-Frame-Options: allow-from https://example.com/

说明

如果设置为 deny,不光在别人的网站 frame 嵌入时会无法加载,在同域名页面中同样会无法加载。另一方面,如果设置为sameorigin,那么页面就可以在同域名页面的 frame 中嵌套。

deny表示该页面不允许在 frame 中展示,即便是在相同域名的页面中嵌套也不允许。

sameorigin表示该页面可以在相同域名页面的 frame 中展示。

allow-from uri表示该页面可以在指定来源的 frame 中展示。

 Apache配置

配置 Apache 在所有页面上发送 X-Frame-Options 响应头,需要把下面这行添加到 ‘site’ 的配置中:


Header always set X-Frame-Options "sameorigin"

要将 Apache 的配置 X-Frame-Options 设置成 deny , 按如下配置去设置你的站点:


Header set X-Frame-Options "deny"

要将 Apache 的配置 X-Frame-Options 设置成 allow-from,在配置这样添加:


Header set X-Frame-Options "allow-from https://example.com/"

nginx配置

配置 nginx 发送 X-Frame-Options 响应头,把下面这行添加到 http, server或者 location 的配置中:


add_header X-Frame-Options sameorigin always;
IIS配置

配置 IIS 发送 X-Frame-Options 响应头,添加下面的配置到 Web.config 文件中:


<system.webServer>
  ...

  <httpProtocol>
    <customHeaders>
      <add name="X-Frame-Options" value="sameorigin" />
    </customHeaders>
  </httpProtocol>

  ...
</system.webServer>

HAProxy配置

配置 HAProxy 发送 X-Frame-Options 头,添加这些到你的前端、监听 listen,或者后端的配置里面:


rspadd X-Frame-Options:\ sameorigin

或者,在更加新的版本中:


http-response set-header X-Frame-Options sameorigin

X-Frame-Options设置后的效果,如下图所示:

设置 meta 标签是无效的!例如 没有任何效果。不要这样用!只有当像上面示例那样设置 HTTP 头 X-Frame-Options 才会生效。

浏览器兼容性

结语

转载请注明:清风博客 » 网页被人恶意嵌入框架(iframe)的处理办法

]]>
https://www.skyfinder.cc/2020/06/24/websiteembediframe/feed/ 0
使用frp搭建内网穿透 https://www.skyfinder.cc/2020/06/06/frp/ https://www.skyfinder.cc/2020/06/06/frp/#respond Sat, 06 Jun 2020 12:56:11 +0000 https://www.skyfinder.cc/?p=2453
背景 由于某些原因需要临时处理一些问题,所以可能需要远程处理。最初使用的是TeamViewer远程控制软件,但是使用频繁会被限制。最后寻找了一个新的解决方案,就是使用内网穿透,而内网穿透的工具选择了FRP。本次内容最终目的是利用FRP可以使用微软系统自带的远程工具进行远程操作。

内网穿透

内网穿透,即NAT穿透,网络连接时术语,计算机是局域网内时,外网与内网的计算机节点需要连接通信,有时就会出现不支持内网穿透。就是说映射端口,能让外网的电脑找到处于内网的电脑,提高下载速度。不管是内网穿透还是其他类型的网络穿透,都是网络穿透的统一方法来研究和解决。

内网穿透应用场景

  • 提供内网穿透服务
  • 连接内网服务器,在外网演示内网web站点
  • 无需服务器部署,快速调试本地程序,方便快速开发微信公众号和微信小程序
  • 支持http、https协议站点,省去证书中间件复杂配置,http协议站点直接升级为https站点
  • 支持TCP,UDP协议端口转发。支持数据库、SSH、远程桌面、网络摄像头等等开放到外网

frp

frp 是一个可用于内网穿透的高性能的反向代理应用,支持 tcp, udp 协议,为 http 和 https 应用协议提供了额外的能力,且尝试性支持了点对点穿透。

frp项目地址

frp开源项目

资源准备

  • 公网服务器一台
  • 个人电脑一台

Frp服务端安装

公网服务器使用的是Linux Centos 7.7,需要下载Frp的Linux版本。

下载地址:https://github.com/fatedier/frp/releases

FRP下载的版本,请根据系统架构类型来选择。

准备将frp放到Linux系统根目录下,所以我先创建一个名为frps的文件夹并下载文件。

cd / && mkdir frps && cd frps && wget  https://github.com/fatedier/frp/releases/download/v0.33.0/frp_0.33.0_linux_amd64.tar.gz

下载完成后,对文件进行解压操作。

tar -xzvf frp_0.33.0_linux_amd64.tar.gz

进入解压后的文件夹

cd frp_0.33.0_linux_amd64

因为使用Linux作为服务端,在这里我们使用的是frps这个文件,所以需要修改frps的配置文件frps.ini.

[common]
# 地址
bind_addr = ip
# frps 服务端端口
bind_port = 端口
# 仪表面板地址
dashboard_addr = ip
# 仪表面板端口
dashboard_port = 端口
# 仪表面板登录用户名
dashboard_user = 用户
# 仪表面板登录用户密码
dashboard_pwd = 密码
# 授权验证方式
authentication_method = token
#  授权验证密钥
token = 密钥
# 最大线程数量
max_pool_count = 5

示例如下:

[common]
bind_addr = 0.0.0.0
bind_port = 5443
dashboard_addr = 0.0.0.0
dashboard_port = 7500
dashboard_user = skyfinder
dashboard_pwd = skyfinderdotcc
authentication_method = token
token = 9ab8b258-8cef-4b12-89d7-2e0c38c2b543
max_pool_count = 5

前台运行frps

./frps -c frps.ini
此种方式运行终端断开,frps服务也同时终止。

设置开机启动和后台运行

在服务器端使用 Systemd 管理 frps。在解压后的目录下有一个名为systemd文件夹,此文件夹下frps.service文件就是我们需要编辑的文件。

cd /frps/frp_0.33.0_linux_amd64/systemd
[Unit]
Description=Frp Server Service
After=network.target

[Service]
Type=simple
User=nobody
Restart=on-failure
RestartSec=5s
ExecStart=/frps/frp_0.33.0_linux_amd64/frps -c /frps/frp_0.33.0_linux_amd64/frps.ini

[Install]
WantedBy=multi-user.target

ExecStart 是要执行文件的路径,调整为我们frps实际的路径。复制到/usr/lib/systemd/system目录。

cp frps.service /usr/lib/systemd/system

启动 frp 并设置开机启动

 
//  frps开机启动
systemctl enable frps
//  启动frps服务
systemctl start frps 
//  frps服务状态  
systemctl status frps 

在某些服务器上可能需要加 .service 后缀,如下


systemctl enable frps.service
systemctl start frps.service
systemctl status frps.service

FRP服务停止与取消开机启动


// 停止frps开机启动
systemctl disable  frps
 
// 停止frps服务
systemctl stop frps  

Windows客户端配置

首先,下载Windows版本的frp,下载完成之后解。

由于我们使用WIndows作为客户端,所以修改frpc.ini配置文件并保存。

[common]
# 服务端IP或域名
server_addr = bj.mlplus.net
# 服务端对应端口
server_port = 5443
# token 要与服务端一致
token =9ab8b258-8cef-4b12-89d7-2e0c38c2b543

# 添加一个远程链接节点 
[mstsc]
# 类型tcp
type = tcp
# 本地IP
local_ip = 127.0.0.1
# 远程链接端口
local_port = 3389
# 此端口和服务端IP或者域名来访问本地电脑
remote_port = 7000
# 是否使用加密
use_encryption = true

在当前目录下打开命令行cmd,输入frpc.exe来运行客户端。

使用远程桌面连接测试是否可用。

转载请注明:清风博客 » 使用frp搭建内网穿透

]]>
https://www.skyfinder.cc/2020/06/06/frp/feed/ 0
梦魇 https://www.skyfinder.cc/2020/05/30/nightmare/ https://www.skyfinder.cc/2020/05/30/nightmare/#respond Fri, 29 May 2020 23:00:00 +0000 https://www.skyfinder.cc/?p=2851

如梦如幻,总那么真实。忽近忽远,还如此清晰。生生死死,依然痛彻心扉。日日夜夜,反复轮回。很多事,终究……

转载请注明:清风博客 » 梦魇

]]>
https://www.skyfinder.cc/2020/05/30/nightmare/feed/ 0
腾讯视频竟然疯狂的偷流量 https://www.skyfinder.cc/2020/05/17/qqliveuploadvideo/ https://www.skyfinder.cc/2020/05/17/qqliveuploadvideo/#respond Sun, 17 May 2020 14:54:23 +0000 https://www.skyfinder.cc/?p=2842 一次意外发现腾讯视频竟然疯狂偷流量,看到了疯狂的上传数据就晓得它在干什么。近7天下载流量接近14G,但是上传流量高达150G。腾讯视频未经允许就将用户作为P2P 节点,为其他用户提供服务。随后也对QQLive进行了限制,不过限制上传流量后没有用,因为它疯狂的开线程。真受不了!!我要卸载它啦!

转载请注明:清风博客 » 腾讯视频竟然疯狂的偷流量

]]>
https://www.skyfinder.cc/2020/05/17/qqliveuploadvideo/feed/ 0
GitHub 现在对团队免费 https://www.skyfinder.cc/2020/05/02/github-is-now-free-for-teams/ https://www.skyfinder.cc/2020/05/02/github-is-now-free-for-teams/#respond Sat, 02 May 2020 05:30:00 +0000 https://www.skyfinder.cc/?p=2809

我们很高兴地宣布,我们将为所有 GitHub 帐户提供具有无限协作功能的私人存储库。所有核心 GitHub 功能现在对每个人都是免费的。

到目前为止,如果您的组织希望将 GitHub 用于私人开发,您必须订阅我们的付费计划之一。但是地球上的每个开发人员都应该能够访问 GitHub。价格不应该是一个障碍。

这意味着团队现在可以在一个地方一起管理他们的工作:CI/CD、项目管理、代码评审、包等等。我们希望每个人都能在开发者喜欢的平台上发布优秀的软件。

需要高级功能(如代码所有者)、企业功能(如 SAML)或个性化支持的 eams 可以升级到我们的付费计划之一。

我们还将付费团队计划的价格从每个用户每月9美元降低到每个用户每月4美元,立即生效。现有客户的账单将自动减少。

在常见问题解答中了解更多信息,或在定价页面上比较计划。

原文地址:https://github.blog/2020-04-14-github-is-now-free-for-teams/

转载请注明:清风博客 » GitHub 现在对团队免费

]]>
https://www.skyfinder.cc/2020/05/02/github-is-now-free-for-teams/feed/ 0