Coder Social home page Coder Social logo

pleaseyang / ity Goto Github PK

View Code? Open in Web Editor NEW
48.0 2.0 20.0 2.68 MB

基于laravel + vue的基础后台,前后端分离,欢迎fork&start,不合理的地方也欢迎批评指正

License: MIT License

PHP 99.10% Batchfile 0.03% HTML 0.87%
laravel jwt vue ity rbac

ity's Issues

`public/cert` 存储商户私钥及证书,可能存在泄漏风险

Ity/app/Models/Config.php

Lines 190 to 202 in b626989

$certificate = self::getCertificate(Storage::path('public/' . $fileinfo['filename'] . '/apiclient_cert.pem'));
// 微信支付平台证书
$wechatPayCertificate = self::getWechatPayCertificatePath($apiV3key, $certificate, Storage::path('public/' . $fileinfo['filename'] . '/apiclient_key.pem'), Storage::path('public/' . $fileinfo['filename']));
$wechatPayCertificateInfo = self::getCertificate(Storage::path('public/' . $fileinfo['filename'] . '/' . $wechatPayCertificate['serialNumber'] . '/wechatpay_cert.pem'));
Storage::deleteDirectory('public/cert');
Storage::makeDirectory('public/cert');
Storage::makeDirectory('public/cert/' . $wechatPayCertificateInfo['serialNumber']);
Storage::copy('public/' . $fileinfo['filename'] . '/apiclient_cert.pem', 'public/cert/apiclient_cert.pem');
Storage::copy('public/' . $fileinfo['filename'] . '/apiclient_key.pem', 'public/cert/apiclient_key.pem');
Storage::copy('public/' . $fileinfo['filename'] . '/' . $wechatPayCertificateInfo['serialNumber'] . '/wechatpay_cert.pem', 'public/cert/' . $wechatPayCertificateInfo['serialNumber'] . '/wechatpay_cert.pem');
Storage::deleteDirectory('public/' . $fileinfo['filename']);

web的根目录是在public,如果没做安全防范,恶意请求可以通过web方式直接下载到商户私钥文件cert/apiclient_key.pem,存在安全隐患。

项目用到了Redis,建议抛弃文件存储,商户私钥、商户证书、平台证书均可以以base64-string形式存储在库中,\WeChatPay\Rsa::from 支持无感加载,详情可参考:

从证书中提取公钥 详见 PHP openssl_x509_parse 返回值。

加载时仅需增加协议即形如 Rsa::from('public.spki://' . $i_am_a_base64_string_without_envelope, Rsa::KEY_TYPE_PUBLIC)

当然Rsa::from也支持原样以文件内容为字符串形式加载私钥及证书,详细用法可参考上述 RsaTest测试用例覆盖方法。

微信支付v3平台证书会在过期前5天会存在两个,建议支持多证书

see https://pay.weixin.qq.com/wiki/doc/apiv3/open/pay/wechatpay5_0.shtml

由于旧证书过期前的5天内,微信支付会同时使用新旧证书,因此为实现新老证书的平滑切换,商户系统需支持多平台证书。

// 根据通知的平台证书序列号,查询本地平台证书文件,
$platformPublicKeyInstance = Rsa::from('file://' . $wechatPayConfig->where('key', 'wechat_pay_cert')->value('value'), Rsa::KEY_TYPE_PUBLIC);
// 检查通知时间偏移量,允许5分钟之内的偏移

建议上述程序逻辑设计,支持多证书加载。

jwt过期后,系统捕获到的异常存在问题,导致无法做无痛刷新token

bug反馈:当把jwt的ttl设置为1分钟后,无痛刷新token存在bug,希望作者核实一下。

操作过程:

1.设置jwt的ttl为1分钟。

2.创建刷新token的middleware,以下是刷新token的中间件代码:

checkForToken($request); //如果格式通过,验证是否是专属于这个的token //获取当前守护的名称 $current_guard = Auth::getDefaultDriver(); //获取当前token $token = Auth::getToken(); //即使过期了,也能获取到token里的载荷信息。 $payload = Auth::manager()->getJWTProvider()->decode($token->get()); //如果不包含guard字段或者guard所对应的值与当前的guard守护值不相同,证明是不属于当前guard守护的token if(empty($payload['guard']) || $payload['guard'] != $current_guard){ throw new TokenInvalidException(); } try{ //检测用户的登录状态,如果正常则通过 if($this->auth->parseToken()->authenticate()){ return $next($request); } throw new UnauthorizedHttpException('jwt-auth','未登录'); }catch(TokenExpiredException $exception){ try{ //刷新用户的token $token = $this->auth->refresh(); //使用一次性登录以保证此次请求的成功 Auth::onceUsingId($this->auth->manager()->getPayloadFactory()->buildClaimsCollection()->toPlainArray()['sub']); //将token存入数据库 $user = Auth::user(); SaveLastTokenJob::dispatch($user,$token); }catch(JWTException $exception) { //如果捕获到此异常,即代表refresh_token也过期了,用户无法刷新令牌,需要重新登录。 throw new UnauthorizedHttpException('jwt-auth', $exception->getMessage()); } } //在响应头中返回新的token return $this->setAuthenticationHeader($next($request), $token); } } 存在的bug: 当token过期后,这行代码$this->auth->parseToken()->authenticate()始终抛出的是UnauthorizedHttpException的exception,导致该中间件无法捕获TokenExpiredException 期望结果: token过期,应该抛出的是TokenExpiredException

建议`chain`用法以标准的`uri_template`方式传参

->chain('v3/pay/transactions/id/' . $transactionId)
->get(['query' => ['mchid' => $merchantId]]);

当然这里的拼接方式是可以工作的,不过仍然建议用标准用法来构造请求,形如:

->chain('v3/pay/transactions/id/{transaction_id}')
->get(['query' => ['mchid' => $merchantId], 'transaction_id' => $transactionId])

另外建议增加依赖 iwechatpay/openapi dev包,上述代码即可以在JB IDE上书写成

->v3->pay->transactions->id->_transaction_id_
->get(['query' => ['mchid' => $merchantId], 'transaction_id' => $transactionId])

即带请求数据结构基础语法提示。

me 接口问题

我运行你的项目,发现me的返回数据,和你示例网站上的不一样。多了一个item。而且permissions 没有值。
{"success":true,"code":200,"locale":"zh-CN","message":"请求成功","data":{"item":{"id":1,"name":"admin","status":1,"email":"[email protected]","email_verified_at":null,"created_at":"2020-12-25 16:13:06","updated_at":"2020-12-25 16:13:06","accessedRoutes":[{"id":1,"pid":0,"path":"/system","component":"layout/Layout","name":"system","meta":{"title":"system","icon":"el-icon-s-tools","roles":[1],"noCache":true,"breadcrumb":true,"affix":false},"hidden":false,"redirect":"noRedirect","children":[{"id":2,"pid":1,"path":"/permission-role","component":"rview","name":"permission-role","meta":{"title":"permission-role","icon":"lock","roles":[1],"noCache":true,"breadcrumb":true,"affix":false},"hidden":false,"redirect":"noRedirect","children":[{"id":3,"pid":2,"path":"permissions","component":"permission/permissions","name":"permission.permissions","meta":{"title":"permission.permissions","icon":"el-icon-key","roles":[1],"noCache":true,"breadcrumb":true,"affix":false},"hidden":false,"children":[{"id":4,"pid":3,"path":"permission/create","component":"permission/create","name":"permission.create","meta":{"title":"permission.create","icon":"icon","roles":[1],"noCache":true,"breadcrumb":true,"affix":false},"hidden":true,"children":[]},{"id":5,"pid":3,"path":"permission/update","component":"permission/update","name":"permission.update","meta":{"title":"permission.update","icon":"icon","roles":[1],"noCache":true,"breadcrumb":true,"affix":false},"hidden":true,"children":[]},{"id":6,"pid":3,"path":"permission/delete","component":"permission/delete","name":"permission.delete","meta":{"title":"permission.delete","icon":"icon","roles":[1],"noCache":true,"breadcrumb":true,"affix":false},"hidden":true,"children":[]},{"id":7,"pid":3,"path":"permission","component":"permission/permission","name":"permission.permission","meta":{"title":"permission.permission","icon":"icon","roles":[1],"noCache":true,"breadcrumb":true,"affix":false},"hidden":true,"children":[]}]},{"id":8,"pid":2,"path":"roles","component":"role/roles","name":"role.roles","meta":{"title":"role.roles","icon":"el-icon-s-custom","roles":[1],"noCache":true,"breadcrumb":true,"affix":false},"hidden":false,"children":[{"id":9,"pid":8,"path":"role/create","component":"role/create","name":"role.create","meta":{"title":"role.create","icon":"icon","roles":[1],"noCache":true,"breadcrumb":true,"affix":false},"hidden":true,"children":[]},{"id":10,"pid":8,"path":"role/update","component":"role/update","name":"role.update","meta":{"title":"role.update","icon":"icon","roles":[1],"noCache":true,"breadcrumb":true,"affix":false},"hidden":true,"children":[]},{"id":11,"pid":8,"path":"role/delete","component":"role/delete","name":"role.delete","meta":{"title":"role.delete","icon":"icon","roles":[1],"noCache":true,"breadcrumb":true,"affix":false},"hidden":true,"children":[]},{"id":12,"pid":8,"path":"role/role","component":"role/role","name":"role.role","meta":{"title":"role.role","icon":"icon","roles":[1],"noCache":true,"breadcrumb":true,"affix":false},"hidden":true,"children":[]},{"id":13,"pid":8,"path":"role/syncPermissions","component":"role/syncPermissions","name":"role.syncPermissions","meta":{"title":"role.syncPermissions","icon":"icon","roles":[1],"noCache":true,"breadcrumb":true,"affix":false},"hidden":true,"children":[]},{"id":14,"pid":8,"path":"role/syncRoles","component":"role/syncRoles","name":"role.syncRoles","meta":{"title":"role.syncRoles","icon":"icon","roles":[1],"noCache":true,"breadcrumb":true,"affix":false},"hidden":true,"children":[]}]}]},{"id":21,"pid":1,"path":"/activeLogs","component":"activeLog/activeLogs","name":"activeLog.activeLogs","meta":{"title":"activeLog.activeLogs","icon":"el-icon-tickets","roles":[1],"noCache":true,"breadcrumb":true,"affix":false},"hidden":false,"children":[]},{"id":22,"pid":1,"path":"/nginxLogs","component":"nginx/logs","name":"nginx.logs","meta":{"title":"nginx.logs","icon":"el-icon-tickets","roles":[1],"noCache":true,"breadcrumb":true,"affix":false},"hidden":false,"children":[]},{"id":23,"pid":1,"path":"/exceptionErrors","component":"exceptionError/exceptionErrors","name":"exceptionError.exceptionErrors","meta":{"title":"exceptionError.exceptionErrors","icon":"el-icon-warning","roles":[1],"noCache":true,"breadcrumb":true,"affix":false},"hidden":false,"children":[{"id":24,"pid":23,"path":"exceptionErrors/amended","component":"exceptionError/amended","name":"exceptionError.amended","meta":{"title":"exceptionError.amended","icon":"el-icon-warning","roles":[1],"noCache":true,"breadcrumb":true,"affix":false},"hidden":true,"children":[]}]},{"id":25,"pid":1,"path":"/exceptionErrors/logFiles","component":"exceptionError/logFiles","name":"exceptionError.logFiles","meta":{"title":"exceptionError.logFiles","icon":"el-icon-tickets","roles":[1],"noCache":true,"breadcrumb":true,"affix":false},"hidden":false,"children":[]},{"id":31,"pid":1,"path":"/files","component":"file/files","name":"file.files","meta":{"title":"file.files","icon":"el-icon-folder","roles":[1],"noCache":true,"breadcrumb":true,"affix":false},"hidden":false,"children":[{"id":32,"pid":31,"path":"file/makeDirectory","component":"file/makeDirectory","name":"file.makeDirectory","meta":{"title":"file.makeDirectory","icon":"el-icon-folder-add","roles":[1],"noCache":true,"breadcrumb":true,"affix":false},"hidden":true,"children":[]},{"id":33,"pid":31,"path":"file/deleteDirectory","component":"file/deleteDirectory","name":"file.deleteDirectory","meta":{"title":"file.deleteDirectory","icon":"el-icon-folder-delete","roles":[1],"noCache":true,"breadcrumb":true,"affix":false},"hidden":true,"children":[]},{"id":34,"pid":31,"path":"file/upload","component":"file/upload","name":"file.upload","meta":{"title":"file.upload","icon":"el-icon-upload","roles":[1],"noCache":true,"breadcrumb":true,"affix":false},"hidden":true,"children":[]},{"id":35,"pid":31,"path":"file/download","component":"file/download","name":"file.download","meta":{"title":"file.download","icon":"el-icon-download","roles":[1],"noCache":true,"breadcrumb":true,"affix":false},"hidden":true,"children":[]},{"id":36,"pid":31,"path":"file/delete","component":"file/delete","name":"file.delete","meta":{"title":"file.delete","icon":"el-icon-delete","roles":[1],"noCache":true,"breadcrumb":true,"affix":false},"hidden":true,"children":[]}]}]},{"id":15,"pid":0,"path":"/admins","component":"layout/Layout","meta":{"title":"admin.admins","icon":"el-icon-user-solid","roles":[1],"noCache":true,"breadcrumb":false,"affix":false},"hidden":false,"children":[{"id":16,"pid":15,"path":"admin/create","component":"admin/create","name":"admin.create","meta":{"title":"admin.create","icon":"icon","roles":[1],"noCache":true,"breadcrumb":true,"affix":false},"hidden":true,"children":[]},{"id":17,"pid":15,"path":"admin/update","component":"admin/update","name":"admin.update","meta":{"title":"admin.update","icon":"icon","roles":[1],"noCache":true,"breadcrumb":true,"affix":false},"hidden":true,"children":[]},{"id":18,"pid":15,"path":"admin/delete","component":"admin/delete","name":"admin.delete","meta":{"title":"admin.delete","icon":"icon","roles":[1],"noCache":true,"breadcrumb":true,"affix":false},"hidden":true,"children":[]},{"id":19,"pid":15,"path":"admin/admin","component":"admin/admin","name":"admin.admin","meta":{"title":"admin.admin","icon":"icon","roles":[1],"noCache":true,"breadcrumb":true,"affix":false},"hidden":true,"children":[]},{"id":20,"pid":15,"path":"admin/syncPermissions","component":"admin/syncPermissions","name":"admin.syncPermissions","meta":{"title":"admin.syncPermissions","icon":"icon","roles":[1],"noCache":true,"breadcrumb":true,"affix":false},"hidden":true,"children":[]},{"path":"index","component":"admin/admins","name":"admin.admins","hidden":false,"meta":{"title":"admin.admins","icon":"el-icon-user-solid","roles":[1],"noCache":true,"breadcrumb":true,"affix":false}}],"redirect":"noRedirect"},{"id":26,"pid":0,"path":"/users","component":"layout/Layout","meta":{"title":"user.users","icon":"el-icon-user","roles":[1],"noCache":true,"breadcrumb":false,"affix":false},"hidden":false,"children":[{"id":27,"pid":26,"path":"user/create","component":"user/create","name":"user.create","meta":{"title":"user.create","icon":"icon","roles":[1],"noCache":true,"breadcrumb":true,"affix":false},"hidden":true,"children":[]},{"id":28,"pid":26,"path":"user/update","component":"user/update","name":"user.update","meta":{"title":"user.update","icon":"icon","roles":[1],"noCache":true,"breadcrumb":true,"affix":false},"hidden":true,"children":[]},{"id":29,"pid":26,"path":"user/delete","component":"user/delete","name":"user.delete","meta":{"title":"user.delete","icon":"icon","roles":[1],"noCache":true,"breadcrumb":true,"affix":false},"hidden":true,"children":[]},{"id":30,"pid":26,"path":"user/user","component":"user/user","name":"user.user","meta":{"title":"user.user","icon":"icon","roles":[1],"noCache":true,"breadcrumb":true,"affix":false},"hidden":true,"children":[]},{"path":"index","component":"user/users","name":"user.users","hidden":false,"meta":{"title":"user.users","icon":"el-icon-user","roles":[1],"noCache":true,"breadcrumb":true,"affix":false}}],"redirect":"noRedirect"},{"path":"*","redirect":"/404","hidden":true}],"roles":["App\Models\Admin\1",1],"unreadNotificationCount":0,"permissions":[]}}}

中间件顺序问题

image

请问一下 这个两个中间件的顺序是在哪指定的吗 按照正常顺序 应该先执行jwt.auth 这个 然后在执行auth:admin 但是现在的顺序是 auth:admin -》jwt.auth 这样的 但是在kernel中也没有看到这个配置顺序 请教一下大佬是在哪指定的

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.