laravel passport加密jwt格式的access_token中的sub(user_id)字段
在很多需求我们不希望别人知道用户在我们表中的 user_id ;
但是又想用数据库的自增 id 功能;
一般时候在取出用户后加密 user_id 加密即可;
但是总有那么几个不经意间就可能把我们的 user_id 暴露了;
比如说 laravel 的 passport ;
创建一个项目用于测试;
安装 passport;
现在我们有了用于测试的 Clint;
将 Laravel\Passport\HasApiTokens Trait
添加到 App\User
模型中;
在 AuthServiceProvider 的 boot 方法中增加 Passport::routes()
;
将 config/auth.php 中的 driver 改为 passport;
创建测试用户
测试用户也有了;
获取下 access_token ;
![](https://baijunyao.com/uploads/article/20190106/5c32110894aa0.png)
我们拿着 access_token 去 jwt.io 解开看下;
![](https://baijunyao.com/uploads/article/20190106/5c32120e76c4c.png)
可以看到 PAYLOAD 中的 sub 就是我们的未加密的用户id;
下面就是将 user_id 加密的过程了;
既然是加密id;
那还需要安装一个扩展包;
示例中我们使用laravel-hashids
随便配置下;
/config/hashids.php
加密用户id;
这里主要用到了 laravel 留的一个钩子;
vendor/laravel/passport/src/Bridge/UserRepository.php
在 getUserEntityByUserCredentials
中会判断 User 模型是否有 findForPassport
方法;
我们可以在此处加密;
app/User.php
因为上面把 user_id 加密了;
而 oauth_access_tokens 表中的 user_id 是 int 类型;
所以我们需要在向 oauth_access_tokens 存储数据的时候自动解密 user_id ;
覆盖 passport 的 OauthAccessToken ;
app/Providers/AuthServiceProvider.php
再获取下 access_token ;
![](https://baijunyao.com/uploads/article/20190106/5c320e14c9036.png)
如我们所愿;
user_id 已经被加密了;
接着还需要处理的是当我们拿着这个token去访问应用的时候能成功验证;
并且可以正确的获取到用户;
定义ExtendedUserProvider 用于覆盖 retrieveById 方法;
app/Extensions/Illuminate/Auth/ExtendedUserProvider.php
修改配置项把 auth.providers.users.driver 改成
config/auth.php
app/Providers/AuthServiceProvider.php
使用 jwt 请求 /api/user 正确的通过的验证
至此通过password
模式的加密和解密已经完成了;
然鹅坑爹的是如果使用authorization code
模式;
因为id是从 code 获取的;
而不是从模型中获取的;
因此我们需要在获取 code 的步骤中加密 user_id ;
先来覆盖原本的 AuthorizationController 中的approve方法;
覆盖路由;
routes/web.php
此处有一个坑爹的地方;
passport 在向 oauth_auth_code 表中存储数据的时候使用了 setRawAttributes
;
以至于我们不能使用 setUserIdAttribute
来解密;
因此需要覆盖 OauthAuthCode 模型的 setRawAttributes
方法用于解密;
app/OauthAuthCode.php
app/Providers/AuthServiceProvider.php
authorization code
模式需要网页登录;
访问 /login
登录;
生成client;
手动组一个获取 code 的 url 并访问;http://passport.test/oauth/authorize?client_id=3&redirect_uri=http://passport.test/auth/callback&response_type=code&scope=
![](https://baijunyao.com/uploads/article/20190106/5c32184f502d4.png)
在回调地址 http://passport.test/auth/callback
页面地址栏获取 code
;
拿着 code
去换取 token
;
![](https://baijunyao.com/uploads/article/20190106/5c3211b3dc1b7.png)
检查 user_id 是否被加密;
![](https://baijunyao.com/uploads/article/20190106/5c3211a45a70e.png)
检测 token 是否可用;
![](https://baijunyao.com/uploads/article/20190106/5c3211958f4ad.png)
一切按着剧本走的没有什么问题;
我把示例代码上传到 github 上了;
如果自己按文章测试的过程中出现问题;
可用参考 https://github.com/baijunyao/laravel-passport-encrypt-user-id-demo