zoukankan      html  css  js  c++  java
  • thinkphp6:前后端分离使用表单令牌(php 8.1.1 / thinkphp v6.0.10LTS/vue 3.2.26)

    一,vue前端代码

    1,Login.vue
    <template>
      <div style="padding:20px;display: flex;align-items:center;justify-content: center;">
        <form :model="account"  style="margin-top:50px;400px;">
            <input v-model="account.username" placeholder="请输入用户名" style="392px;font-size:16px;" /><br/>
            <input v-model="account.password"  type="password" placeholder="请输入密码" style="392px;margin-top:10px;font-size:16px;" /><br/>
            <!--v-loading.fullscreen.lock="isLoading"-->
            <div    @click="login"  style="margin-top:10px; 100%;height:40px;line-height:40px;background: #ff0000;border-radius: 10px;">
              登录
            </div>
          <div    @click="info"  style="margin-top:10px; 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 formToken = ref("");
        const getToken = () => {
          apiToken().then(res => {
            //成功
            if (res.code == 0) {
              formToken.value = res.data.token;
            } else {
              ElMessage.error("获取表单令牌失败:"+res.msg);
            }
          }).catch((error) => {
            console.log(error)
          })
        }
        getToken();
    
        //登录
        const login = async () => {
          console.log('begin login');
          var data = new FormData();
          data.append("username",account.username);
          data.append("password",account.password);
          data.append("X-CSRF-TOKEN",formToken.value);
    
              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) {
               console.log(res.data);
            } else {
              ElMessage.error("用户信息获取失败:"+res.msg);
            }
    
          }).catch((error) => {
            console.log(error)
          })
        }
    
        return {
          account,
          accountRef,
          login,
          login2,
          info,
        };
      },
    }
    </script>
    
    <style scoped>
    </style>
    2,api/axios.js
    ...
    //post
    export function postForm (url, params) {
      return new Promise((resolve, reject) => {
          let headers = {
              'Content-Type': 'application/x-www-form-urlencoded',
          }
          //判断params中是否包含X-CSRF-TOKEN
          var token = "";
          if (params.has("X-CSRF-TOKEN")) {
              token = params.get("X-CSRF-TOKEN");
              params.delete("X-CSRF-TOKEN");
              headers = {
                  'Content-Type': 'application/x-www-form-urlencoded',
                  'X-CSRF-TOKEN': token,
              }
          }
    
        _axios.post(url, params,{headers})
            .then(res => {
              resolve(res.data)
            })
            .catch(err => {
                console.log("api error:");
                console.log(err);
                //alert(err);
              reject(err.data)
            })
      })
    }
    ...

    3,api/api.js

    //get,
    import { get, postForm} from './axios'
    
    //user
    export const apiLogin = pLogin => postForm('/api/auth/login', pLogin)
    ...

    说明:刘宏缔的架构森林是一个专注架构的博客,地址:https://www.cnblogs.com/architectforest

             对应的源码可以访问这里获取: https://github.com/liuhongdi/
             或: https://gitee.com/liuhongdi

    说明:作者:刘宏缔 邮箱: 371125307@qq.com

    二,服务端代码:

    1,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
    {
           /*
         *得到form token
         *
         *@return \think\Response
         * */
        public function token():Json {
            $type="sha1";
            $type  = is_callable($type) ? $type : 'md5';
            $token = call_user_func($type, $this->request->server('REQUEST_TIME_FLOAT'));
            $key = uniqid();
            Cache::set($key,$token,300);
            $res = [
                "token"=>$key.$token,
                ];
            return Result::Success($res);
        }
    
        /**
         * 登录
         *
         * @return \think\Response
         */
        public function login():Json {
            // Header验证
            if ($this->request->header('X-CSRF-TOKEN')){
                $reqToken = $this->request->header('X-CSRF-TOKEN');
                $key = substr($reqToken,0,13);
                $value = Cache::get($key);
                $origToken = $key.$value;
                if ($origToken === $reqToken) {
                    //验证通过
                } else {
                    //验证不通过
                    return Result::Error(422,'表单token错误');
                }
            } else {
                return Result::Error(423,'找不到表单token');
            }
            try {
                validate(LoginValidate::class)
                    ->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,"用户名密码错误");
            }
        }
    } 
    2,Result.php
     
    <?php
    
    namespace app\result;
    use think\response\Json;
    class Result {
        //success
        static public function Success($data):Json {
            $rs = [
                'code'=>0,
                'msg'=>"success",
                'data'=>$data,
            ];
            return json($rs);
        }
        //error
        static public function Error($code,$msg):Json {
            $rs = [
                'code'=>$code,
                'msg'=>$msg,
                'data'=>"",
            ];
            return json($rs);
        }
    }

    三,测试效果:

    1,界面
    2,  提交与返回:

    四,查看vue的版本

    liuhongdi@lhdpc:/data/vue/demo1$ npm list vue
    demo1@0.1.0 /data/vue/demo1
    ├─┬ @vue/cli-plugin-babel@4.5.15
    │ └─┬ @vue/babel-preset-app@4.5.15
    │   └── vue@3.2.26 deduped
    ├─┬ element-plus@1.2.0-beta.6
    │ ├─┬ @element-plus/icons-vue@0.2.4
    │ │ └── vue@3.2.26 deduped
    │ ├─┬ @vueuse/core@7.4.1
    │ │ ├─┬ @vueuse/shared@7.4.1
    │ │ │ └── vue@3.2.26 deduped
    │ │ ├─┬ vue-demi@0.12.1
    │ │ │ └── vue@3.2.26 deduped
    │ │ └── vue@3.2.26 deduped
    │ └── vue@3.2.26 deduped
    └─┬ vue@3.2.26
      └─┬ @vue/server-renderer@3.2.26
        └── vue@3.2.26 deduped 

    五,查看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 
  • 相关阅读:
    Confluence 6 LDAP 服务器配置
    在 Confluence 6 中连接一个 LDAP 目录
    Confluence 6 设置公共访问
    Confluence 6 为站点禁用匿名用户访问
    Confluence 6 为站点启用匿名用户访问
    Confluence 6 配置用户目录
    Confluence 6 设置公共访问备注
    Confluence 6 为空间赋予公共访问
    Confluence 6 更新目录
    Omad群组部署、依赖部署一键解决
  • 原文地址:https://www.cnblogs.com/architectforest/p/15776927.html
Copyright © 2011-2022 走看看