thinkphp6: 前后端分離:用jwt+middleware做用戶登錄驗證(php 8.1.1 / thinkphp v6.0.10LTS )


一,安裝firebase/php-jwt擴展:

1,命令:
liuhongdi@lhdpc:/data/php/admapi$ composer require firebase/php-jwt
2,安裝成功后的位置:
3,查看firebase/php-jwt的版本:
liuhongdi@lhdpc:/data/php/admapi$ composer show firebase/php-jwt

說明:劉宏締的架構森林是一個專注架構的博客,

網站:https://blog.imgtouch.com
本文: https://blog.imgtouch.com/index.php/2023/05/29/thinkphp6-qian-hou-duan-fen-li-yong-jwt-middleware-zuo-yong/

         對應的源碼可以訪問這里獲取: https://github.com/liuhongdi/
         或: https://gitee.com/liuhongdi

說明:作者:劉宏締 郵箱: 371125307@qq.com

二,前端vue代碼:

Login.vue

<template>
  <div style="padding:20px;display: flex;align-items:center;justify-content: center;">
    <form :model="account"  style="margin-top:50px;width:400px;">
        <input v-model="account.username" placeholder="請輸入用戶名" style="width:392px;font-size:16px;" /><br/>
        <input v-model="account.password"  type="password" placeholder="請輸入密碼" style="width:392px;margin-top:10px;font-size:16px;" /><br/>
        <!--v-loading.fullscreen.lock="isLoading"-->
        <div    @click="login"  style="margin-top:10px;width: 100%;height:40px;line-height:40px;background: #ff0000;border-radius: 10px;">
          登錄
        </div>
      <div    @click="info"  style="margin-top:10px;width: 100%;height:40px;line-height:40px;background: #ff0000;border-radius: 10px;">
        info
      </div>
        <div class="text-align-right">
        </div>
    </form>
  </div>
</template>

<script>
import { ref,  reactive } from "vue";
import { ElMessage } from "element-plus";
import { apiLogin,apiInfo,apiToken} from '@/api/api';
export default {
  name: "Login",
  setup() {
    const accountRef = ref(null);
    //表單字段
    const account = reactive({
      username: "",
      password: "",
    });

    //登錄
    const login = async () => {
      console.log('begin login');

      var data = new FormData();
      data.append("username",account.username);
      data.append("password",account.password);
          apiLogin(data).then(res => {
            //成功
            if (res.code == 0) {
              //保存jwt token到本地
              localStorage.setItem('token', res.data.token);
              //提示
              ElMessage.success("登錄成功!");

            } else {
              ElMessage.error("登錄失敗:"+res.msg);
            }

          }).catch((error) => {
            console.log(error)
          })
    };

    const login2 = () => {
      console.log('begin login2');
    }

    const info = () => {
      apiInfo().then(res => {
        //成功
        if (res.code == 0) {
          //保存jwt token到本地
          //localStorage.setItem('token', res.data.token);
          //提示
          //ElMessage.success("登錄成功!");
           console.log(res.data);
        } else {
          ElMessage.error("用戶信息獲取失敗:"+res.msg);
        }
      }).catch((error) => {
        console.log(error)
      })
    }
    return {
      account,
      //loginRules,
      accountRef,
      login,
      login2,
      info,
      //isLoading,
    };
  },
}
</script>

<style scoped>
</style>

 

三,后端php代碼:

1,創建middleware
liuhongdi@lhdpc:/data/php/admapi$ php think make:middleware CheckJwt
Middleware:app\middleware\CheckJwt created successfully. 
2,CheckJwt的代碼: 
<?php
declare (strict_types = 1);

namespace app\middleware;

use app\lib\util\JwtUtil;

class CheckJwt
{
    /**
     * 處理請求,得到用戶信息
     *
     * @param \think\Request $request
     * @param \Closure       $next
     * @return Response
     */
    public function handle($request, \Closure $next)
    {
        $auth = $request->header('authorization');
        if ($auth == null) {
            return $next($request);
        }
        $token = str_replace("Bearer ","",$auth);
        $jUtil = new JwtUtil();
        $res = $jUtil->verifyjwt($token);
        if (isset($res['code']) && isset($res['userId']) && $res['code'] == 0 && is_int($res['userId'])) {
            $userId = $res['userId'];
            $request->auth = $userId;
        } else {
            $request->auth = 0;
        }
        return $next($request);
    }
}

3,app/middleware.php

使從jwt得到用戶信息的middleware生效:

<?php
// 全局中間件定義文件
return [
    app\middleware\CheckJwt::class,
];

4,controller/Auth.php

<?php
declare (strict_types = 1);

namespace app\controller;

use app\BaseController;
use think\facade\Cache;
use think\Request;
use app\result\Result;
use think\response\Json;
use app\validate\Login as LoginValidate;
use app\validate\GoodsList as GoodsListValidate;
use think\exception\ValidateException;
use app\lib\util\JwtUtil;

class Auth extends BaseController
{
    /**
     * 登錄
     *
     * @return \think\Response
     */
    public function login():Json {
        try {
            validate(LoginValidate::class)
                //->scene('edit')
                ->check($_POST);
        } catch (ValidateException $e) {
                // 驗證失敗 輸出錯誤信息
                return Result::Error(422,$e->getError());
        }

        if ($_POST["username"] == "dddddd" && $_POST["password"] == "111111"){
            //驗證成功,生成jwt返回
            $userId = 123;
            $jUtil = new JwtUtil();
            $token = $jUtil->createJwt($userId);
            $res = ["token"=>$token];
            // 防止重復提交
            Cache::delete($key);
            return Result::Success($res);
        } else {
            return Result::Error(422,"用戶名密碼錯誤");
        }
    }
    /**
     * 得到用戶信息
     *
     * @return \think\Response
     */
    public function info()
    {
        if ($this->request->auth > 0) {
            $status = "已登錄";
        } else {
            $status = "未登錄";
        }

        $info = [
            'userId'=>$this->request->auth,
            'status'=>$status,
        ];
        return Result::Success($info);
    }
}

5,lib/util/JwtUtil.php

<?php
namespace app\lib\util;

use Firebase\JWT\ExpiredException;
use Firebase\JWT\JWT;

class JwtUtil {

    private $signKey = "lhd@2001:liuhongdi";
    private $timeMinutes = 5;
    /**
     * 根據json web token設置的規則生成token
     * @return \think\response\Json
     */
    public function createJwt($userId):string
    {
        $key = md5($this->signKey); //jwt的簽發**,驗證token的時候需要用到
        $time = time(); //簽發時間
        $expire = $time + $this->timeMinutes*60; //過期時間
        $token = array(
            "userId" => $userId,
            "iss" => "http://www.liuhongdi.com/",//簽發組織
            "aud" => "lhd", //簽發作者
            "iat" => $time,    //簽發時間
            "nbf" => $time,    //生效時間
            "exp" => $expire    //過期時間
        );
        $jwt = JWT::encode($token,$key);
        return $jwt;
    }

    /**
     * 驗證token
     * @return \think\response\Json
     */
    public function verifyjwt($token)
    {
        $key = md5($this->signKey); //jwt的簽發**,驗證token的時候需要用到
        try{
            $jwtAuth = json_encode(JWT::decode($token,$key,array("HS256")));
            $authInfo = json_decode($jwtAuth,true);
            if (!$authInfo['userId']){
                return ['code'=>0,'msg'=>"用戶不存在"];
            }
            return ['code'=>0,'userId'=>$authInfo['userId'],'msg'=>"ok"];
        }catch (ExpiredException $e){
            return ['code'=>0,'msg'=>"token過期"];
        }catch (\Exception $e){
            return ['code'=>0,'msg'=>$e->getMessage()];
        }
    }
}

 

四,效果測試

1,界面:用戶名 dddddd,密碼;111111,可見php的代碼:

2,未登錄時點info

3,登錄后的返回:

4,登錄后查看info的返回:

五,查看php和thinkphp的版本:

php:
liuhongdi@lhdpc:/data/php/admapi$ php --version
PHP 8.1.1 (cli) (built: Dec 20 2021 16:12:16) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.1.1, Copyright (c) Zend Technologies
    with Zend OPcache v8.1.1, Copyright (c), by Zend Technologies 
thinkphp:
liuhongdi@lhdpc:/var/www/html$ cd /data/php/admapi/
liuhongdi@lhdpc:/data/php/admapi$ php think version
v6.0.10LTS 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM