清风博客 https://www.skyfinder.cc 关注IT世界,记录平凡生活 Tue, 08 Sep 2020 09:57:30 +0000 zh-CN hourly 1 https://wordpress.org/?v=5.5.1 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
Redis Desktop Manager 2020.1.0.0 https://www.skyfinder.cc/2020/05/02/redis-desktop-manager-201950/ https://www.skyfinder.cc/2020/05/02/redis-desktop-manager-201950/#respond Fri, 01 May 2020 17:01:26 +0000 https://www.skyfinder.cc/?p=2795 Redis Desktop Manager(又名RDM)—是用于Windows,Linux和MacOS的快速开源Redis数据库管理应用程序。该工具为您提供了易于使用的GUI,以访问您的Redis数据库并执行一些基本操作:以树的形式查看密钥,CRUD密钥,通过Shell执行命令。RDM支持SSL / TLS加密,SSH隧道和云Redis实例。

Redis Desktop Manager 客户端在最初是免费的,可以自由使用。后来作者实施了收费策略,也就是说现在它不免费提供编译版本。但是它是开源的,作为开发者可以自行编译使用,当然大部分人懒得编译,我就是这样的。

新功能

  • 允许按名称打开密钥而不扫描数据库

修复

  • 固定冻结多行键中的大值
  • 提高SSH连接上TLS的稳定性

官方下载

Redis Desktop ManageRedis Desktop Manage

免付费/编译版本

Redis Desktop Manager Windows/MAC版本:提取码:hkwg

以上Redis Desktop Manager本包含Windows系统和MAC,其中Windows的版本是Redis Desktop Manager 2020.1.0.0,MAC的版本是2020.0.79。

如果资金宽裕,请尽量使用付费版本,以便支持软件更好的发展。

转载请注明:清风博客 » Redis Desktop Manager 2020.1.0.0

]]>
https://www.skyfinder.cc/2020/05/02/redis-desktop-manager-201950/feed/ 0
HTML 5游戏捉住小猫 https://www.skyfinder.cc/2020/04/25/html5game/ https://www.skyfinder.cc/2020/04/25/html5game/#respond Sat, 25 Apr 2020 14:03:10 +0000 https://www.skyfinder.cc/?p=2739 在某个网站出现的404页面,看到了一个有意思HTML5的抓猫小游戏,于是就找了源文件,迁移到自己博客。 其实在此之前本博客的404页面也是一个同样的抓猫游戏,只不过是flash版本的,由于Chrome浏览器升级后flash就被禁用了,这个游戏就从页面移除了。

游戏玩法

  • 点击小圆点,围住小猫。
  • 你点击一次,小猫走一次。
  • 直到你把小猫围住(赢),或者小猫走到边界并逃跑(输)。

项目

GIT开源项目抓猫游戏本博下载

转载请注明:清风博客 » HTML 5游戏捉住小猫

]]>
https://www.skyfinder.cc/2020/04/25/html5game/feed/ 0
Office 2016密钥 https://www.skyfinder.cc/2020/04/22/office-2016-key/ https://www.skyfinder.cc/2020/04/22/office-2016-key/#respond Wed, 22 Apr 2020 02:00:00 +0000 https://www.skyfinder.cc/?p=2730 使用的Office 2016过期了,所以就再全网找相关密钥以及激活工具。最后找到了一些密钥并且激活成功,在这里做一下记录。

以下密钥仅作学习OFFICE技能之用,如果商用请购买正版。

Office 2016 ProPlusVL_MAK(Office 2016专业增强批量授权版)

DNMXF-HKQR2-CRJ7F-BFHHK-C7J3Y
V9NQG-MM8GX-XDDP8-KRRMH-BDW3Y
8YNGW-PW6KQ-V6BG7-JCP4X-QV7BB
QYG29-Y8NVR-YRXPY-T3DVW-GVJ3Y
6NVBG-T9JK9-HDXDG-3JVXM-G3BVM

以上密钥何时失效暂不可知,如果不可用则为失效。

转载请注明:清风博客 » Office 2016密钥

]]>
https://www.skyfinder.cc/2020/04/22/office-2016-key/feed/ 0
Linux系统下使用split分割大文件 https://www.skyfinder.cc/2020/04/17/linuxsplitbigfile/ https://www.skyfinder.cc/2020/04/17/linuxsplitbigfile/#respond Fri, 17 Apr 2020 04:00:00 +0000 https://www.skyfinder.cc/?p=2715 split命令

split可以指定按行数分割和按字节大小分割两种模式。

语法

split [--help][--version][-d][-<行数>][-b <字节>][-C <字节>][-l <行数>][要切割的文件][输出文件名]

参数

参数说明
-<行数>或-l<行数>指定每多少行就要切成一个小文件。
-b<字节>指定每多少字就要切成一个小文件。支持单位:m,k
-d分割使用数字后缀
-C<字节>与-b参数类似,但切割时尽量维持每行的完整性。
--help 显示帮助。
--version显示版本信息
--verbose显示分割进度

按行数

split -l 具体行数 -d  要分割的大文件  新文件名前缀

例如:

split -l 1000 -d  2020-04-17.log  new_file_prefix_

按字节大小

split -b 具体的字节大小 -d  要分割的大文件  新文件名前缀

例如:

split -b 500m -d  2020-04-17.log  new_file_prefix_ --verbose

合并

 cat命令

cat  文件名前缀 > 新文件名

例如:

cat new_file_prefix_* > merge_newfile.log

转载请注明:清风博客 » Linux系统下使用split分割大文件

]]>
https://www.skyfinder.cc/2020/04/17/linuxsplitbigfile/feed/ 0
CSS层叠样式表实现全站灰度(grayscale ) https://www.skyfinder.cc/2020/04/04/cssgrayscale/ https://www.skyfinder.cc/2020/04/04/cssgrayscale/#respond Sat, 04 Apr 2020 01:00:00 +0000 https://www.skyfinder.cc/?p=2679 为表达全国各族人民对抗击新冠肺炎疫情斗争牺牲烈士和逝世同胞的深切哀悼,国务院今天发布公告,决定2020年4月4日举行全国性哀悼活动。在此期间,全国和驻外使领馆下半旗志哀,全国停止公共娱乐活动。4月4日10时起,全国人民默哀3分钟,汽车、火车、舰船鸣笛,防空警报鸣响。而各大网站均实现全站灰度,腾讯视频、爱奇艺停止所有娱乐类型视频入口。

实现全站灰度可以使用CSS或者使用其他JS插件处理,例如:grayscale js。本博使用的是CSS处理全站灰度,代码示例如下:


html {
-webkit-filter: grayscale(100%);
-moz-filter: grayscale(100%);
-ms-filter: grayscale(100%);
-o-filter: grayscale(100%);
filter:progid:DXImageTransform.Microsoft.BasicImage(grayscale=1);
_filter:none;
}

转载请注明:清风博客 » CSS层叠样式表实现全站灰度(grayscale )

]]>
https://www.skyfinder.cc/2020/04/04/cssgrayscale/feed/ 0
C#实现图片压缩 https://www.skyfinder.cc/2020/04/04/csharpimagecompress/ https://www.skyfinder.cc/2020/04/04/csharpimagecompress/#respond Fri, 03 Apr 2020 16:00:00 +0000 https://www.skyfinder.cc/?p=2666 有些时候会在博客中分享一些拍摄的照片,而这些拍摄照片的大小均在1.5M以上,随随便便分享点图片占用的存储空间就有点惊人。为了节省存储空间,避免尽早将剩余存储空间消耗完毕,所以就考虑压缩一下图片。这里来做下记录。


using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;

namespace ImageCompress
{
    class Program
    {
        static void Main(string[] args)
        {
            string path = $"{Path.Combine(Directory.GetCurrentDirectory(), "image")}";
            CompressionImageProcess.CompressionImage($"{Path.Combine(path, "IMG_20200308_161707.jpg")}",$"{Path.Combine(path, "compression")}",50);
            Console.WriteLine("OK");
        }
    }
    public class CompressionImageProcess
    {
        public static void CompressionImage(string imagePath, string targetfolder, long quality = 100)
        {
            if (!File.Exists(imagePath))
            {
                throw new FileNotFoundException();
            }
            if (!Directory.Exists(targetfolder))
            {
                Directory.CreateDirectory(targetfolder);
            }
            FileInfo fileInfo = new FileInfo(imagePath);
            string fileName = fileInfo.Name.Replace(fileInfo.Extension, "");
            string fileFullName = Path.Combine($"{targetfolder}", $"{fileName}{fileInfo.Extension}");

            var iamgeByte = CompressionImage(imagePath, quality);
            MemoryStream ms = new MemoryStream(iamgeByte);
            Image image = System.Drawing.Image.FromStream(ms);
            image.Save(fileFullName);
            ms?.Close();
            ms?.Dispose();
            image?.Dispose();
        }
        private static byte[] CompressionImage(string imagePath, long quality)
        {
            using (FileStream fileStream = new FileStream(imagePath, FileMode.Open))
            {
                using (System.Drawing.Image img = System.Drawing.Image.FromStream(fileStream))
                {
                    using (Bitmap bitmap = new Bitmap(img))
                    {
                        ImageCodecInfo CodecInfo = GetEncoder(img.RawFormat);
                        System.Drawing.Imaging.Encoder myEncoder = System.Drawing.Imaging.Encoder.Quality;
                        EncoderParameters myEncoderParameters = new EncoderParameters(1);
                        EncoderParameter myEncoderParameter = new EncoderParameter(myEncoder, quality);
                        myEncoderParameters.Param[0] = myEncoderParameter;
                        using (MemoryStream ms = new MemoryStream())
                        {
                            bitmap.Save(ms, CodecInfo, myEncoderParameters);
                            myEncoderParameters?.Dispose();
                            myEncoderParameter?.Dispose();
                            return ms.ToArray();
                        }
                    }
                }
            }
        }

        private static ImageCodecInfo GetEncoder(ImageFormat format)
        {
            ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();
            foreach (ImageCodecInfo codec in codecs)
            {
                if (codec.FormatID == format.Guid)
                {
                    return codec;
                }
            }
            return null;
        }
    }
}


下图大小为1.5M,压缩质量设置了50,压缩后的大小为306.6k,压缩前后的质量清晰度还可以接受。

示例下载

图片压缩示例
其实示例代码写完就觉得自己有点傻,发现WordPress图片压缩插件也有不少,以后能省则省吧!

转载请注明:清风博客 » C#实现图片压缩

]]>
https://www.skyfinder.cc/2020/04/04/csharpimagecompress/feed/ 0
C#实现大文本文件切割/分割 https://www.skyfinder.cc/2020/04/03/csharpcutbigfile/ https://www.skyfinder.cc/2020/04/03/csharpcutbigfile/#respond Fri, 03 Apr 2020 01:00:00 +0000 https://www.skyfinder.cc/?p=2646 因某些原因,需要打开日志进行排查,本来是很简单的事情,当看到日之后就觉得力不从心。日志文件太大了,将近5G,自己电脑打不开这种大文件。一开始就想到了文件分割,然后就再网上找一些分割工具,找了几个分割工具杀毒软件都报毒。找工具也真是个麻烦的事情,找到半天没有见到一个合适的。其中一个不报毒(主动查杀了一次)的,双击后也打不开,这个时候我就怀疑自己中招(中毒)了,到底有没有中招暂时不太清楚,所以赶紧利用杀毒软件查杀病毒。在查杀病毒的期间自己就动手使用C#写一个简单的文本文件分割工具。这里就记录一下.


using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;

namespace TxtFileCutApart
{
    class Program
    {
        static void Main(string[] args)
        {
            if (args.Length < 3)
            {
                Console.WriteLine("缺少参数。");
                return;
            }
            if (!File.Exists(args[0]))
            {
                Console.WriteLine("分割文件不存在");
                return;
            }
            if (!Directory.Exists(args[1]))
            {
                Console.WriteLine("分割目录不存在");
                return;
            }
            long size = Convert.ToInt64(args[2]);
            List types = new List() {"size","count","row" };
            Dictionary dicFileCut = new Dictionary() { {"size",new TxtFileCutApartFileSize() }, { "count", new TxtFileCutApartFileCount() } , { "row", new TxtFileCutApartRows() } };
            string type =types[0];
            if (args.Length == 4&&types.Contains(args[3]))
            {
                type =args[3];
            }
            Console.WriteLine("开始分割,请稍候……");
            Stopwatch st = new Stopwatch();
            TxtFileCutApart txtFileCut = dicFileCut[type];
            st.Start();
            txtFileCut.FileCut(args[0],args[1],size);
            st.Stop();
            Console.WriteLine($"完成,耗时:{st.ElapsedMilliseconds/1000}s");
        }
    }

    public abstract class TxtFileCutApart
    {
        public abstract void FileCut(string sourcePath, string targetFolder,long size);
    }
    public  class TxtFileCutApartFileCount : TxtFileCutApart
    {
        public override void FileCut(string sourcePath, string targetFolder, long fileCount)
        {
            if (fileCount <= 0)
            {
                return;
            }
            FileInfo fileInfo = new FileInfo(sourcePath);
            string fileName = fileInfo.Name.Replace(fileInfo.Extension, "");
            long fileLength = fileInfo.Length;
            FileStream fsRead = new FileStream(sourcePath, FileMode.Open, FileAccess.Read, FileShare.Read);
            BinaryReader br = new BinaryReader(fsRead);
            int defaultBurrerLength = 1024 * 1024;
            long fileSizeLength = Convert.ToInt64((Math.Ceiling(fileLength / Convert.ToDouble(fileCount))));
            byte[] buffer = new byte[defaultBurrerLength];
            int readLength = 0;
            int fileIndex = 1;
            long readFileLength = 0;
            while (readFileLength < fileLength)
            {
                string writeFile = Path.Combine(targetFolder, $"{fileName}_{fileIndex}{fileInfo.Extension}");
                FileStream fsWrite = new FileStream(writeFile, FileMode.CreateNew, FileAccess.Write);
                BinaryWriter bw = new BinaryWriter(fsWrite);
                long singleFileLength = 0;
                while ((readLength = br.Read(buffer, 0, buffer.Length)) > 0)
                {
                    bw.Write(buffer, 0, readLength);
                    readFileLength += readLength;
                    singleFileLength += readLength;
                    if (singleFileLength >= fileSizeLength)
                    {
                        bw?.Close();
                        bw?.Dispose();
                        fsWrite?.Close();
                        fsWrite?.Dispose();
                        break;
                    }
                }
                bw?.Close();
                bw?.Dispose();
                fsWrite?.Close();
                fsWrite?.Dispose();
                fileIndex++;
            }
            br?.Close();
            br?.Dispose();
            fsRead?.Close();
            fsRead.Dispose();
        }
    }
    public  class TxtFileCutApartFileSize : TxtFileCutApart
    {
        public override void FileCut(string sourcePath, string targetFolder, long fileSize)
        {
            if (fileSize <= 0)
            {
                return;
            }
            FileInfo fileInfo = new FileInfo(sourcePath);
            string fileName = fileInfo.Name.Replace(fileInfo.Extension, "");

            FileStream fsRead = new FileStream(sourcePath, FileMode.Open, FileAccess.Read, FileShare.Read);
            BinaryReader br = new BinaryReader(fsRead);
            int defaultBurrerLength = 1024 * 1024;
            long fileSizeLength = fileSize * defaultBurrerLength;
            byte[] buffer = new byte[defaultBurrerLength];
            int readLength = 0;
            int fileIndex = 1;
            long fileLength = fileInfo.Length;
            long readFileLength = 0;
            while (readFileLength < fileLength)
            {
                string writeFile = Path.Combine(targetFolder, $"{fileName}_{fileIndex}{fileInfo.Extension}");
                FileStream fsWrite = new FileStream(writeFile, FileMode.CreateNew, FileAccess.Write);
                BinaryWriter bw = new BinaryWriter(fsWrite);
                long singleFileLength = 0;
                while ((readLength = br.Read(buffer, 0, buffer.Length)) > 0)
                {
                    bw.Write(buffer, 0, readLength);
                    readFileLength += readLength;
                    singleFileLength += readLength;
                    if (singleFileLength >= fileSizeLength)
                    {
                        bw?.Close();
                        bw?.Dispose();
                        fsWrite?.Close();
                        fsWrite?.Dispose();
                        break;
                    }
                }
                bw?.Close();
                bw?.Dispose();
                fsWrite?.Close();
                fsWrite?.Dispose();
                fileIndex++;
            }
            br?.Close();
            br?.Dispose();
            fsRead?.Close();
            fsRead.Dispose();
        }
    }
    public  class TxtFileCutApartRows: TxtFileCutApart
    {
        public override void FileCut(string sourcePath, string targetFolder, long row)
        {
            if (row <= 0)
            {
                return;
            }
            FileInfo fileInfo = new FileInfo(sourcePath);
            string fileName = fileInfo.Name.Replace(fileInfo.Extension, "");
            string lineData = "";
            StreamReader sr = new StreamReader(sourcePath);
            StreamWriter sw = null;

            long readEowIndex = 1, index = 1;
            while ((lineData = sr.ReadLine()) != null)
            {
                if (sw == null || readEowIndex >= row)
                {
                    sw?.Close();
                    sw?.Dispose();
                    string _fileName = Path.Combine(targetFolder, $"{fileName}_{index}{fileInfo.Extension}");
                    sw = new StreamWriter(_fileName);
                    readEowIndex = 1;
                    index++;
                }
                if (row >= readEowIndex)
                {
                    sw.WriteLine(lineData);
                    sw.Flush();
                    readEowIndex++;
                }
            }
            sw?.Close();
            sw?.Dispose();
            sr?.Close();
            sr.Dispose();
        }
    }
}

小的切割工具可以按照大小(兆)、按照文件数量、按照行来进行分割。

dotnet TxtFileCutApart.dll 文件路径 分割后保存目录 数值 分割类型

具体使用方法,如下图所示:

源码下载

C#超大文本文件分割小工具

转载请注明:清风博客 » C#实现大文本文件切割/分割

]]>
https://www.skyfinder.cc/2020/04/03/csharpcutbigfile/feed/ 0