laravel:用户认证之 lcobucci/jwt 4.0.4(10.27.0)

news/发布时间2024/8/25 11:13:10

一,安装第三方库 

1,官方代码站:

https://github.com/lcobucci/jwt

文档地址:

https://lcobucci-jwt.readthedocs.io/en/latest/

2,用composer安装

liuhongdi@lhdpc:/data/laravel/dignews$ composer require lcobucci/jwt

3,安装后查看库的版本:

liuhongdi@lhdpc:/data/laravel/dignews$ composer show lcobucci/jwt
name     : lcobucci/jwt
descrip. : A simple library to work with JSON Web Token and JSON Web Signature
keywords : JWS, jwt
versions : * 4.0.4
type     : library
...

二,php代码

1,封装类:App\extend\jwt\JwtUtil.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
<?php
 
namespace App\extend\jwt;
 
use Lcobucci\JWT\Configuration;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use Lcobucci\JWT\Signer\Key\InMemory;
/**
 * 单例模式
 * Class JwtUtil
 * @package App\extend\jwt
 */
class JwtUtil
{
    private $config;
    private $key = "Ge1KCTRhdVsmUUZY0GrwgEvLubPvLOCM";
    private $iss = "liuhongdi.com";//颁发者(iss声明)
    private $aud = "liuhongdiauth.com";//访问群体(aud声明)
    private $jti = "5t6y9400453"; //id(jti声明)
    private $expTime = 1;//令牌有效时间,单位小时
    private static $instance;// 单例模式JwtAuth句柄
 
    // 获取JwtAuth的句柄
    public static function getInstance()
    {
        if (is_null(self::$instance)) {
            self::$instance = new self();
        }
        return self::$instance;
    }
 
    /**
     * 构造
     */
    public function __construct()
    {
        self::init();
    }
 
    /**
     * 初始化
     */
    private function init()
    {
        $config = Configuration::forSymmetricSigner(
            new Sha256(),
            InMemory::base64Encoded($this->key)
        );
        $this->config = $config;
    }
 
    /**
     * 创建JWT
     * @param array $arrClaim
     * @return string
     * @throws \Exception
     * @author 老刘
     */
    public function createToken(array $arrClaim)
    {
        $config = $this->config;
        assert($config instanceof Configuration);
        if (is_array($arrClaim) && count(array_filter(array_keys($arrClaim),'is_string'))>0) {
            //是关联数组
        } else {
            //不是关联数组
            throw new \Exception("claim参数必须为关联数组");
        }
 
        $now = new \DateTimeImmutable();
 
        $token = $config->builder()
            // 配置颁发者(iss声明)
            ->issuedBy($this->iss)
            // 配置访问群体(aud声明)
            ->permittedFor($this->aud)
            // 配置id(jti声明)
            ->identifiedBy($this->jti)
            // 配置令牌发出的时间(iat声明)
            ->issuedAt($now)
            // 配置令牌的过期时间(exp claim)
            ->expiresAt($now->modify("+{$this->expTime} hour"));
        //claim
        foreach ($arrClaim as $k => $item) {
            $token = $token->withClaim($k, $item);
        }
        // 生成新令牌
        $token = $token->getToken($config->signer(), $config->signingKey());
        return $token->toString();
    }
 
    /**
     * 解析token
     * @param string $jwt
     * @return mixed
     * @author 老刘
     */
    public function parseToken(string $jwt)
    {
        $config = $this->config;
        $token = $config->parser()->parse($jwt);
        return $token->claims();
    }
 
 
    /**
     * 验证令牌
     * @param $jwt
     * @return mixed
     * @throws \Exception
     * @author 老刘
     */
    public function validatorToken($jwt)
    {
        $config = $this->config;
        $token = $config->parser()->parse($jwt);
        $claims = $token->claims();
        $jti = (string)$claims->get('jti');
        $iss = (string)$claims->get('iss');
        $aud = $claims->get('aud');
        $exp = $claims->get('exp');
        $now = new \DateTimeImmutable();
        // 是否过期
        if ($exp < $now) {
            throw new \Exception("身份已过期");
        }
        //验证jwt id是否匹配
        $validate_jwt_id = new \Lcobucci\JWT\Validation\Constraint\IdentifiedBy($jti);
        // 验证签发人url是否正确
        $validate_issued = new \Lcobucci\JWT\Validation\Constraint\IssuedBy($iss);
        // 验证客户端url是否匹配
        $validate_aud = new \Lcobucci\JWT\Validation\Constraint\PermittedFor($aud[0]);
        $config->setValidationConstraints($validate_jwt_id, $validate_issued, $validate_aud);
        $constraints = $config->validationConstraints();
        //验证
        if (!$config->validator()->validate($token, ...$constraints)) {
            throw new \Exception("非法的请求");
        }
        return $claims;
    }
}

2,创建controller:

liuhongdi@lhdpc:/data/laravel/dignews$ php artisan make:controller LoginController

   INFO  Controller [app/Http/Controllers/LoginController.php] created successfully.

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
<?php
 
namespace App\Http\Controllers;
 
use Illuminate\Http\Request;
use App\extend\result\Result;
use App\Models\Staff as StaffModel;
use App\business\StaffLogin;
use Illuminate\Support\Facades\Redis;
use App\extend\jwt\JwtUtil;
 
class LoginController extends Controller
{
    /**
     * 得到用户信息
     */
    public function info(Request $request)
    {
        //得到数据库的用户id
        $staffId = $request->auth;
        $staff = new StaffModel();
        $rows = $staff->getOneByStaffId($staffId);
        if (is_null($rows)) {
            return Result::ErrorCode(100,'用户不存在');
        }
        unset($rows['password']);
        //添加头像
        $host = "http://192.168.219.6/imgstaffhead";
        $rand = rand(1000,9999);
        $rows['head'] = $host."/".$staffId.".jpg?rand=".$rand;
        //返回
        return Result::Success($rows);
    }
 
    //得到jwt信息,返回给线下
    function getJwtInfo($userId,$nickName) {
        //验证成功,生成jwt返回
        //$jUtil = new JwtUtil();
        //$token = $jUtil->createJwt($userId);
        $token = JwtUtil::getInstance()->createToken(['uid' => $userId]);
        $res = ["tokenString"=>$token];
 
        $host = "http://192.168.219.6/imgstaffhead";
        $rand = rand(1000,9999);
        $res['head'] = $host."/".$userId.".jpg?rand=".$rand;
        $res['nickname'] = $nickName;
        return $res;
    }
     
    /**
     * 登录
     *
     */
    public function login(Request $request) {
         
        $username = $request->post('username');
        $password = $request->post('password');
 
        $uniqid = $request->post('uniqid');
        $captcode = $request->post('captcode');
        //检查验证码:
        $value = Redis::get($uniqid);
        if (strtolower($captcode) !== strtolower($value)) {
            return Result::ErrorCode(400,"输入的验证码不正确");
        }
 
        //用username读取用户信息
        $staff = new StaffModel();
        $rows = $staff->getOneByUsername($username);
        if ($rows == null) {
            return Result::ErrorCode(422,'用户名出现错误');
        } else {
            if ($rows['is_active'] == 0) {
                return Result::ErrorCode(422,'用户未激活');
            } else {
                //检查密码是否正确
                if (password_verify($password,$rows['password'])) {
                    $res = $this->getJwtInfo($rows['staff_id'],$rows['nickname']);
                    //登录成功,写日志
                    $loginLog = new StaffLogin();
                    $loginLog->log($rows['staff_id']);
                    return Result::Success($res);
                } else {
                    //报密码错误
                    return Result::ErrorCode(422,"用户名密码错误");
                }
            }
        }
    }
}

3,创建middleware

liuhongdi@lhdpc:/data/laravel/dignews$ php artisan make:middleware JwtAuth

   INFO  Middleware [app/Http/Middleware/JwtAuth.php] created successfully.

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<?php
 
namespace App\Http\Middleware;
 
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
 
use App\extend\jwt\JwtUtil;
 
class JwtAuth
{
    /**
     * Handle an incoming request.
     *
     * @param  \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response)  $next
     */
    public function handle(Request $request, Closure $next): Response
    {
        //得到jwt的token
        $auth = $request->header('authorization');
        if ($auth == null) {
            return $next($request);
        }
        $token = str_replace("Bearer ","",$auth);
        if (count(explode('.', $token)) <> 3) {
            throw new \Exception('非法身份信息,请重新登录', -1);
        }
        //检验token
        $objJwtAuth = JwtUtil::getInstance();
        $claims = $objJwtAuth->validatorToken($token);
        //得到用户id
        $uid = $claims->get('uid');
        //添加到request
        $request->merge(['auth'=>$uid]);
        return $next($request);
    }
}

三,vue代码:

api/axios.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
import axios from 'axios'
import { ElMessage } from "element-plus";
import router from "../route/router.js"
import { getUser } from '@/utils/user'
 
import { showLoading, hideLoading } from '@/utils/loading'
let config = {
    timeout:10000,
};
 
const _axios = axios.create(config);
//request interceptor
_axios.interceptors.request.use(
    function(config) {
        showLoading();
        //在发送请求前,增加token字串到header
        let userInfo = getUser().data;
        if ('tokenString' in userInfo && userInfo["tokenString"] != ""){
            config.headers.Authorization ="Bearer "+userInfo["tokenString"];
        }
      return config;
    },
    function(error) {
      // Do something with request error
      return Promise.reject(error);
    }
);
 
//response interceptor
_axios.interceptors.response.use(
    function(response) {
        hideLoading();
        let code = response.data.code;
        if (code == '401') {
            //现在跳转去登录
            let redi = {path: router.currentRoute.value.fullPath};
            let redistr = JSON.stringify(redi);
            if (router.currentRoute.value.meta.redirectstr) {
                redistr = router.currentRoute.value.meta.redirectstr;
            }
            //打印出参数
            if (router.currentRoute.value.meta.actstr) {
                let actstr = router.currentRoute.value.meta.actstr;
                router.replace({ path: '/login/login',query: { redirect: redistr,act:actstr } });
            } else {
                router.replace({ path: '/login/login',query: { redirect: redistr } });
            }
 
        }
      return response;
    },
    function(error) {
        hideLoading();
      // Do something with response error
        if (error.response.status) {
            //alert(error.response.status);
            switch (error.response.status) {
                // 401: 未登录
                // 未登录则跳转登录页面,并携带当前页面的路径
                // 在登录成功后返回当前页面,这一步需要在登录页操作。
                case 401:
                    router.replace({ path: '/login/login' });
                    break;
                // 403 token过期
                // 登录过期对用户进行提示
                // 清除本地token和清空vuex中token对象
                // 跳转登录页面
                case 403:
                    ElMessage.error("登录过期,请重新登录");
                    // 清除token
                    localStorage.removeItem('token')
                    // 跳转登录页面,并将要浏览的页面fullPath传过去,登录成功后跳转需要访问的页面
                    setTimeout(() => {
                        router.push({ path: '/login/login' });
                    }, 1000)
                    break;
                // 404请求不存在
                case 404:
                    ElMessage.error("网络请求不存在,404错误");
                    break;
                // 500服务端错误
                case 500:
                    ElMessage.error("服务端有故障,500错误");
                    break;
                // 其他错误,直接抛出错误提示
                default:
                    var tip = "";
                    if (typeof(error.response.data.message) == "undefined") {
                        tip = error.toString();
                    } else {
                        tip = error.response.data.message;
                    }
                    ElMessage.error(tip);
                    break;
            }
            return Promise.reject(error.response)
        }
    }
);
 
/**
 * get方法,对应get请求
 * @param {String} url [请求的url地址]
 * @param {Object} params [请求时携带的参数]
 */
export function get (url, params) {
  return new Promise((resolve, reject) => {
    _axios.get(url, {
      params: params,
    }).then(res => {
      resolve(res.data)
    }).catch(err => {
      reject(err.data)
    })
  })
}
 
//postForm
export function post (url, params) {
  return new Promise((resolve, reject) => {
    _axios.post(url, params,{headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
    }})
        .then(res => {
          resolve(res.data)
        })
        .catch(err => {
          reject(err.data)
        })
  })
}

说明:刘宏缔的架构森林—专注it技术的博客,
网站:https://blog.imgtouch.com
原文: https://blog.imgtouch.com/index.php/2023/10/31/laravel-yong-hu-ren-zheng-zhi-lcobucci-jwt-10-27/
代码: https://github.com/liuhongdi/ 或 https://gitee.com/liuhongdi
说明:作者:刘宏缔 邮箱: 371125307@qq.com

四,测试效果:

五,查看laravel框架的版本:

liuhongdi@lhdpc:/data/laravel/dignews$ php artisan --version
Laravel Framework 10.27.0

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.liansuoyi.cn/news/08400267.html

如若内容造成侵权/违法违规/事实不符,请联系连锁易网进行投诉反馈email:xxxxxxxx@qq.com,一经查实,立即删除!

相关文章

Go语言基准测试(benchmark)三部曲之一:基础篇

通过实战熟悉和掌握Go语音的基准测试(benchmark),本篇是最基本和最常用的操作欢迎访问我的GitHub这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos关于基准测试(benchmark)Go的标准库内置的testing框架提供了基准测试(benchmark)功能,可以…

面向程序设计语言LLVM杂谈

面向程序设计语言LLVM杂谈如何为特定语言表达式生成 LLVM IR,请搜索接受相应对象的方法。 例如,对于 if-else 语句: IRCodegenVisitor::codegenExprIR Value *IRCodegenVisitor::codegen(const ExprIfElseIR &expr) {... // this is the LLVM IR generation } 了解 LLVM…

6-1 使用函数的选择法排序

目录 目录目录题目代码思路图问题 题目 本题要求实现一个用选择法对整数数组进行简单排序的函数。 函数接口定义: void sort( int a[], int n ); 其中a是待排序的数组,n是数组a中元素的个数。该函数用选择法将数组a中的元素按升序排列,结果仍然在数组a中。 裁判测试程序样例…

iMessage群发,苹果iMessage短信,苹果iMessage推信,电脑版Mac Os系统自动群发iMessage完美实现 - 电脑端升级版

一、PC电脑版苹果系统(Mac OS)上实现imessage群发总结为以下几种方式: /*MacOS苹果系统,正常情况下,只能安装到苹果公司自己出品的Mac电脑,俗称白苹果,不能安装到各种组装机或者其他品牌的品牌机上,黑苹果的的原理,就是通过一些 “破解补丁” 工具欺骗macOS系统,让苹果系统…

BurpSuite经常拦截firefox报文如success.txt的解决办法

因为工作需要经常使用Burp对收发报文进行检测,平时习惯使用火狐浏览器,但是火狐浏览器经常进行一些登录状态的检测,导致Burp拦截中出现大量的火狐报文,如http://detectportal.firefox.com/success.txt。这些报文与测试业务无关,但是数据量又很大,非常影响工作效率,这里提…

Chromium Canvas工作流

blink 中实现了2种 canvas,分别是 blink::HTMLCanvasElement 和 blink::OffscreenCanvas ,前者对应 html/dom 中的 canvas,后者对应 js 中的 OffscrenCanvas。 html canvas 有两种模式,一种是常规模式,这种模式下 canvas 的绘制时机受 viz/cc 的调度,和网页上的其他 dom …

浅析Redis大Key

在京东到家购物车系统中,用户基于门店能够对商品进行加车操作。用户与门店商品使用Redis的Hash类型存储,如下代码块所示。不知细心的你有没有发现,如果单门店加车商品过多,或者门店过多时,此Key就会越来越大,从而影响线上业务。一、背景 在京东到家购物车系统中,用户基于…

你怎么看待软件测试中的性能测试

性能测试一、什么是性能测试 1、百度百科上性能测试是:通过自动化的测试工具模拟不同场景的负载条件,去探究系统设计与资源消耗之间的平衡,从而实现对系统各项指标的检测和测试。 2、我们可以把性能测试理解为:应用软件中各项指标的负载情况。通过在测试环境下对系统或构件…

本体论介绍 (2)

本文内容预告 本体论定义,一些常见的关于本体论的术语汇总,一些真实本体论的例子。 本体论的定义 知识图谱领域学术论文中,对本体论 (Ontology) 的定义有很多,这里只介绍其中一种: 本体论是对某个专业领域内的所共识的概念和它们之间关系的显示的和正式的细化定义 (Specia…

读图数据库实战笔记04_路径与图变异

路径与图变异1. Groovy 1.1. Java编程语言的一个超集 1.2. Gremlin Console的一个特性是能和Groovy配合使用 1.2.1. Gremlin Console会自动地迭代结果 1.3. 从技术上说,Gremlin Console就是Groovy交互式解释器(read-eval-print loop,REPL) 1.3.1. 既可以作为一个独立的程序…

crypto常用算法

欧几里得算法(辗转相除法)def gcd(a, b):if b == 0:return aelse:return gcd(b, a % b) 扩展欧几里得算法def ext_euclid(a, b): if b == 0: return 1, 0, a else: x, y, q = ext_euclid(b, a % b) x, y = y, (x - (a // b) * y) return x, y, q 大步小步算法(BSG…

crypto常用工具

古典密码 维吉尼亚密码(Vigenere): https://github.com/atomcated/Vigenere(加密解密程序,包含自动猜测密钥功能) https://www.guballa.de/vigenere-solver whitespace语言: https://ideone.com/ gmpy2 from gmpy2 import *mpz(n) #初始化一个大整数 mpfr(x) # 初始化一…

LLVM代码生成分析杂谈

LLVM代码生成分析杂谈 1简介 本文提供了有关生成和编译LLVM程序集代码的其他信息。 LLVM是一个庞大而复杂的系统,用于为各种目标体系结构生成优化的机器代码。对于这个项目,将使用其功能的非常有限的子集,为了方便使用,定义了一个生成LLVM代码的简单接口,可以在示例代码的…

一文分清OMS、CMS、PMS、TMS、IM、BI、BPMS、SCRM、DSS等B端系统

1、OMS系统 OMS系统是Order Management System的缩写,中文名为订单管理系统。它是一种电子商务系统,主要用于管理订单、库存、物流和客户服务等方面的业务流程。OMS系统可以帮助企业实现订单的自动化处理、库存管理、物流跟踪和客户服务等功能,提高订单处理效率和准确度,降…

Conftest.py+fixture+yield 实现⽤例前置后置

通过Conftest.py+fixture+yield,可轻松实现⽤例前置后置,包括项⽬级的项目目录下创建conftest.py文件:#coding=gbk import pytest @pytest.fixture() def fix1():print("\n开始执⾏fix1")yieldprint("\n结束执⾏fix1")文件同级别下创建test_case_01.py文…

Web SSH 的原理与在 ASP.NET Core SignalR 中的实现

前言 有个项目,需要在前端有个管理终端可以 SSH 到主控机的终端,如果不考虑用户使用 vim 等需要在控制台内现实界面的软件的话,其实使用 Process 类型去启动相应程序就够了。而这次的需求则需要考虑用户会做相关设置。 原理 这里用到的原理是伪终端。伪终端(pseudo termina…

32-TIM输出比较

输出比较(OC) 通过比较CNT和CCR寄存器值的关系,来对输出电平进行置1、置0或翻转的操作。用于输出一定频率和占空比的PWM波形。上图中蓝色线是CNT,它的值不断自增,橙色线是ARR,当CNT的值自增到ARR中设定阈值时,清零。红色线是CCR的值,通过CNT与CCR的比较,根据PWM的模式…

CVE-2020-0022 蓝牙漏洞复现

CVE-2020-0022 蓝牙漏洞复现CVE-2020-0022参考连接: CVE-2020-0022 蓝牙漏洞初探(上)一个bug引发的血案-安全客 - 安全资讯平台 (anquanke.com) CVE-2020-0022 “BlueFrag”漏洞分析 (bestwing.me) Diff - 3cb7149d8fed2d7d77ceaa95bf845224c4db3baf^! - platform/system/bt…

使用Raspberry Pi和OpenPLC项目进行PLC编程1简介

0 前言 0.1 书籍介绍 本书旨在向读者介绍如何将Raspberry Pi计算机作为PLC(可编程逻辑控制)用于他们的项目。 该项目要感谢程序员 Edouard Tisserant 和 Mario de Sousa。他们在 2003年IEC 61131-3标准出台后启动了"Matiec 项目"。这使得将标准中引入的编程语言翻译…
推荐文章