缘起
近来开发个活动报名站,后端使用 Ruby on Rails,前端使用 Vue。由于是SPA,传统的 cookie 法就不太适宜,使用流行的 JWT。因此选用 Devise Token Auth gem 来处理用户模型与 token 发行、验证等工作。
密码重置流程
其他模块使用正常且方便。而忘记密码重置涉及到邮件,reset link 发行等就显得麻烦。根据官方 wiki 记载 reset password flow
- 在前端页面中填写邮箱地址输入框,有按钮可以发送重置邮件
POST /auth/passwordJSON: {email, redirect_url}这里 redirect_url 为前端页面,有填写密码框- 后端生成
reset_password_token与链接填入邮件,形如http://localhost:3000/api/v1/auth/password/edit?config=default&redirect_url=http%3A%2F%2Flocalhost%3A8080%2Freset&reset_password_token=L77a9yx2JHehPCgVoQ2_- 前端跳转 redirect url
- 前端用
reset_password_token、client、uid 作 headersPUT /auth/password完成重置
观察链接,发现其中包含reset_password_token与redirect_url,点击跳转前端链接 http://localhost:8080/reset?
access-token=D3zacAdKrGwRPxcQ-9rnXQ&
client=CwF0zNBw9ovM3KmHaCmIIg&
client_id=CwF0zNBw9ovM3KmHaCmIIg&
config=default&expiry=1538140242&reset_password=true&
token=D3zacAdKrGwRPxcQ-9rnXQ&
uid=1%40e.com
可见 headers 信息都有包含在 URL
问题
网络中 devise token auth 重置密码相关的文章中使用 MVC,API的相对少,用 Vue 就更少。还得自己摸索。
问题1: hash 路径错位
最初在项目中 Vue-router 使用 hash 模式,故在请求 json 中填写 redirect_url 包含 #。而 rails 处理后忽略掉 # 造成路径错误,这里可以改用 history 模式解决。URL 中的参数可用 route.query 取出。
另有 router navigation guard 的应设定确保不跳转,不然链接变成 http://localhost:8080/reset?
access-token=D3zacAdKrGwRPxcQ-9rnXQ&
client=CwF0zNBw9ovM3KmHaCmIIg&
client_id=CwF0zNBw9ovM3KmHaCmIIg&
config=default&expiry=1538140242&reset_password=true&
token=D3zacAdKrGwRPxcQ-9rnXQ&uid=1%40e.com#/login
这里本人设定未登录跳转登录页,跳转信息与重置 URL 混杂造成混乱。
Vue 复用密码修改组件(若有登录后修改选项的话)可抽离 request 函数,通过判别是否有登录信息(如 Vuex state、sessionStorage)构造不同的 headers 发送请求。
问题2: 后端路径 host 变前端 host(password#edit)
原来 devise token anth 生成 reset password url 时取前端 host name,要是后端域名与之不同就出错。如前端 a.com,后端b.com,则邮件中生成 http://a.com/api/v1/auth/password/edit?...。看起来默认当作 MVC,是同域。
而在本地测试时同域端口不同没发现问题,可见靠同域不同端口区分。而部署到服务器用 80,443 端口就不区分了,怎么办呢?最后反代前端 /api 到 rails 解决。如 caddy 写法:
# 前端a.com { root /var/www/xxx}
# 将错误路径导向 apia.com/api { proxy / locahost:3000/api { transparent }}
# 后端b.com { proxy / locahost:3000 { transparent }}Bonus: custom Devise Token Auth registration controller
设定用户删除账户时会同时删除创建的活动、与报名信息(人都跑路,活动显然没了,报名也吹了)防止出错(活动详细页获取不到创建人信息,报名信息有 null)
Devise Token Auth 中 用户注册、删除在 registration controller,默认删除操作只是完成用户删除不管别的。这时需要自定义。创建自定义类继承基类
class Users::RegistrationsController < DeviseTokenAuth::RegistrationsController def destroy @resource.events.each(&:destroy) @resource.bookings.each(&:destroy) super endend由于在基类中已经获取到资源
module DeviseTokenAuth class RegistrationsController < DeviseTokenAuth::ApplicationController before_action :set_user_by_token, only: [:destroy, :update] # 这里 return @resource因此可以直接使用,而不是向 super 加块处理。因为 super 的方法中块在 destroy 后
def destroy if @resource @resource.destroy yield @resource if block_given? #destroy 后找不到用户相关联的活动 render_destroy_success else render_destroy_error end end后记
其他问题好找,这个就没有了(估计第一篇Rails 5 API + Devise Token Auth + Vue 的密码重置流)。完成这个也算尾声了,现在将要部署,而 production 如何设定,dockerfile 如何写就一脸懵逼。若有运维可以赐教就感激不尽。
分享文章
生成精美分享图或复制链接,与更多人分享本文。
继续阅读
换条路线
从其他文章中稳定抽取
最后更新于 ,距今已过 2918 天
部分内容可能已过时
评论