Firebase JWT库Token验证的使用

By heiry on 2024-06-02 [ in 技术 ]

项目中使用Firebase JWT库做Token验证,确实很好用,减少了很多繁琐的判断,不过要使用它自带的验证方法,命名就必须符合它的标准。

如,起始时间,过期时间等都需要按照它的标准命名:

 

$tokenData = [
'iat' => $issuedAt, //Token核发时间,标准写法,名称固定为 iat
'exp' => $expirationTime, //Token过期时间 ,标准写法,名称固定为 exp
];

验证非常方便,只需要调用相应的异常结果就可以了,不必自己拆解出来做复杂的判断。

 

 

try {
                $decoded = JWT::decode($token, new Key($this->secretKey, 'HS256'));
                $decodeToken = (array)$decoded;
            } catch (ExpiredException $e) {//过期异常
                $message = 'Token has expired';
                $outData = ['code' => 401, 'message' => $message];
                return json($outData);
            } catch (SignatureInvalidException $e) { //签名不正确,被篡改
                 $message = 'Invalid token signature';
                $outData = ['code' => 401, 'message' => $message];
                return json($outData);
            } catch (Exception $e) { //格式不符或者被篡改
                $message = 'Token validation failed';
                $message = 'Verify Fail: permission denied';
                $outData = ['code' => 401, 'message' => $message];
                return json($outData);
            }


 

 

 

>> 阅读全文  >>

使用Fabric的一些心得

By heiry on 2024-06-02 [ in 技术 ]

最近项目中使用Fabric.js做图像动态标记,被有些小问题缠住,花了很多时间去琢磨,有些甚至弄了一两天才理明白,特此记录。

1.canvas的width、height与style.width、style.height须一致,否则画出图形会变形或只显示图像的一部分。

canvasRef.value.width = img.naturalWidth;
canvasRef.value.height = img.naturalHeight;
canvasRef.value.style.width = img.naturalWidth + 'px';
canvasRef.value.style.height = img.naturalHeight + 'px';

看资料,fabric的画布实际上有三层(下图来自:jb51)

2.可以创建离屏/静态画布,不必在页面中显示,整体绘制完毕后再通过图像对象输出。

 

const canvas = new fabric.StaticCanvas(null, {
width: originWidth,
height: originHeight
});

离屏画布的节点引用设置为null,一样可以设置宽高。

3. 如果有背景图片,所有创建的元素都需要在创建背景图片的函数体内完成,不能在函数体外创建,否则导出的图片将背景不可见。就是这个问题,我困扰了两天,开始以为是跨域问题,背景图片格式的问题等等,后来发现原因在此。

nextTick(
      () => {
        canvasRef.value.width = img.naturalWidth;
        canvasRef.value.height = img.naturalHeight;
        canvasRef.value.style.width = img.naturalWidth + 'px';
        canvasRef.value.style.height = img.naturalHeight + 'px';
        let currentCanvas = new fabric.Canvas(canvasRef.value, {
          selectionColor: '#4fb8d3',
          selectionLineWidth: 0
        });

        fabric.Image.fromURL(imgUrl, (img) => {  //必须将绘制的文本和图形放到这个背景图函数体内,否则无法显示背景图
          currentCanvas.setBackgroundImage(
            img,
            currentCanvas.renderAll.bind(currentCanvas)
          );
          currentCanvas.backgroundImage.scaleToWidth(currentCanvas.width);
          currentCanvas.backgroundImage.scaleToHeight(currentCanvas.height);
          for (let key in LocationObj) {
            let locationNum = LocationObj[key][0].bbox;
            let arr = locationNum.split(',');
            let numberArray = arr.map(Number);
            let rect = new fabric.Rect({
              left: numberArray[0],
              top: numberArray[1],
              width: numberArray[2] - numberArray[0],
              height: numberArray[3] - numberArray[1],
              fill: 'transparent',
              stroke: 'rgb(235,64,64,0.9)',
              strokeWidth: 3,
              strokeDashArray: [5, 5]
            });
            let text = new fabric.Text(
              ' ' +
                messageMap.value[key] +
                ' - ' +
                Number(LocationObj[key][0].conf) * 100 +
                '%' +
                ' ',
              {
                left: numberArray[0], // 文本的X坐标  
                top: numberArray[1] - 22,
                fontSize: 22, // 字体大小
                textBackgroundColor: '#eb4040', // 文字背景颜色
                textBackgroundColor: 'rgb(235,64,64,0.8)',
                hasControls: false, // 不显示控件
                hasBorders: false, // 不显示边框
                fontWeight: 'normal',
                fill: 'white',
                padding: 20,
                lineHeight: 3,
                textAlign: 'right',
                fontFamily: 'Arial,Microsoft YaHei'
              }
            );
            currentCanvas.add(rect);
            currentCanvas.add(text);
            currentCanvas.renderAll();  
            // rect.set('selectable', false);
            // text.set('selectable', false);
          }

          downURL.value = currentCanvas.toDataURL({
            format: 'png',
            quality: 0.9
          });
          downLink.value.download = 'X_RayImg.png';
        });
      },
      { crossOrigin: 'Anonymous' }
    );

 

 

 

>> 阅读全文  >>

OracleCloud的VPS问题汇总

By heiry on 2021-04-27 [ in 技术 ]

Oracle的云服务较之国内有很多便利,也没那么多套路,但新上手还是有很多不顺之处。

1.OracleCloud创建的主机,是不能自己配置公网IP的,也看不到绑定公网IP的网卡,只能看到一块ens3的默认网卡,绑定的是内网IP。

[root@instance-heiry ~]# [root@instance-heiry ~]# ifconfig -a
ens3: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 9000
        inet 10.0.0.86  netmask 255.255.255.0  broadcast 10.0.0.255
        inet6 fe80::17ff:fe00:7ee5  prefixlen 64  scopeid 0x20<link>
        ether 02:00:17:00:7e:e5  txqueuelen 1000  (Ethernet)
        RX packets 42717  bytes 79644892 (75.9 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 39782  bytes 17319192 (16.5 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

2.默认以opc+key登录,root被禁用,每次SSH之后都要sudo -i 才能执行相应操作,非常麻烦,需要手动更改:

sudo -i
sudo passwd root
Changing password for user root.
New password:
#打开PasswordAuthentication及 PermitRootLogin功能
vim /etc/ssh/sshd_config
#把值设为yes,去掉注释
PasswordAuthentication yes
PermitRootLogin yes
#重启SSH服务
service sshd restart

3.默认有security list 控制入站规则,除了在服务器设定开放端口外, security list 也需要设置Ingress Rules才能访问。

4.使用ubuntu 系统默认装 iptables-persistent,需要手动设置。centOS8下安装mysql8.0,出现莫名其妙的问题, security list开放了3306访问,服务器防火墙也开启了3306,mysql服务器权限都设置了,但是在启用服务器防火墙情况下,始终无法远程访问mysql服务器,如关闭,则可以访问。即使mysqld服务占用的3306/33060端口都开放,监听了所有IP,仍然无法访问。

发现3306端口只是在TCP6下监听,于是将

vim /etc/mysql/my.cnf 
#加上参数
bind-address = 0.0.0.0

设置IPv4转发状态

sysctl net.ipv4.ip_forward
vim /etc/sysctl.conf
#添加以下参数
net.ipv4.ip_forward = 1

发现,3306转到tcp下监听,可是打开防火墙,远程依然是被blocked状态。

 

>> 阅读全文  >>

vim高频实用命令整理

By heiry on 2019-09-11 [ in 技术 ]

进入编辑/输入模式

快捷命令 功能描述
i 在当前光标所在位置插入随后输入的文本,光标后的文本相应向右移动
I 在光标所在行的行首插入随后输入的文本,行首是该行的第一个非空白字符,相当于光标移动到行首执行 i 命令
o 在光标所在行的下面插入新的一行。光标停在空行首,等待输入文本
O 在光标所在行的上面插入新的一行。光标停在空行的行首,等待输入文本
a 在当前光标所在位置之后插入随后输入的文本
A 在光标所在行的行尾插入随后输入的文本,相当于光标移动到行尾再执行 a 命令

光标移动操作

快捷命令 功能描述
w 向前移动,光标停留在下个单词词首,每次一个单词(单词中不含其他字符如:- \ = +等)在当前光标所在位置插入随后输入的文本,光标后的文本相应向右移动
nw 向后移动n个word(n可以是任意整数数字,如2w)后续W、b、B、e、E都可这样使用
W 向前移动,光标停留在下个单词词首,每次一个字符串(字符串可以含有其字符如:- \ = +等,is-a word/and/bog 这种都是字串)
b 向后移动,光标停留在前个单词词首,每次一个单词
B 向后移动,光标停留在前个单词词首,每次一个字符串在光标所在行的上面插入新的一行。光标停在空行的行首,等待输入文本
e 向前移动,光标停留在前个单词词尾,每次一个单词
E 向前移动,光标停留在前个单词词尾,每次一个字符串在光标所在行的行尾插入随后输入的文本,相当于光标移动到行尾再执行 a 命令
Home 快速移动光标至当前行首
End 快速移动光标至当前行尾
:n 移动到第n行,如,:10可快速跳转到10行
gg 移动到文本开始处
G 移动到文本末尾处
nG 光标移动到第 n 行,n 为数字
0 或 ^ 移动至当前行的行首
$ 移动至当前行的行尾
n$ 移动至当前行只有 n 行的行尾,n为数字
fx 移动至当前行中下一个 x 字符处,如,fe,则移动到下一个e字母处
Fx 移动至当前行中上一个 x 字符处,如,fe,则移动到下上个e字母处
nj 向下移动n行,如,10j表示向下移动10行
ctrl+b 向上翻页
ctrl+f 向下翻页

撤销操作

快捷命令 功能描述
u 撤销上一次的操作
U 行撤销,撤销所有在前一个编辑行上的操作(行恢复)。

查找操作

快捷命令 功能描述
/str 在后面的文本中查找str。
?str 在前面的文本中查找str。
n 向后查找下一个。
N 向前查找下一个。

复制粘贴

快捷命令 功能描述
yy 单行复制
dd 单行删除(剪切)
p 粘贴
按esc键后,先按gg(到达顶部),然后dG 全部删除
按esc键后,先按gg,然后ggyG 全部复制
n 向后查找下一个。
N 向前查找下一个。
>> 阅读全文  >>

设计模式剖析系列之快照/备忘录模式

By heiry on 2019-08-23 [ in 技术 ]

快照/备忘录模式

快照模式也称为备忘录模式,其作用是将捕获对象的状态保存起来,在需要的时候可以进行恢复。

核心结构:

A.源发器 Originator类,对象的基本状态信息类,其含两个核心方法,其一是备份操作的setMemento()方法,该方法返回一个备份对象Memento实例。另一个是恢复操作的recovery(Memento m)方法,其需要传入一个已经备份的Memento实例。

B. 快照Memento类,用于创建源发器实例的快照。其属性包含了源发器所有属性。构造方法需要传入一个需要备份的源发器Originator类实例。

C. 快照管理类,用于关联已经创建的快照对象实例。

以上三者关系及客户端调用方法如下图所示: (更多…)

>> 阅读全文  >>

设计模式剖析系列之状态模式

By heiry on 2019-08-21 [ in 技术 ]

状态模式详解

当控制一个对象状态转换的条件表达式过于复杂,把状态的判断逻辑转移到对应的状态类中,实现复杂逻辑的简单化,这是状态模式的初衷。状态模式的核心组成要点:

1. 抽象状态接口或类State:封装状态行为。

2. 具体状态类 Concrete State:实现抽象State类或接口的行为,每个状态对应一个类。

3. 环境类 Context:用于实现状态的转换与客户端的调用,其包含了对一个对State实例的引用。

状态模式示意图

 

>> 阅读全文  >>

设计模式剖析系列之策略模式

By heiry on 2019-08-21 [ in 技术 ]

策略模式定义了一系列算法(算法族),各可以相互替换,客户端可根据实际情况选择使用哪一种算法,算法的变化不会影响使用算法的客户。

策略模式核心结构: (更多…)

>> 阅读全文  >>


© 2009-2024 MOSANG.NET DESIGNED BY HEIRY