Rails后端+KotlinJs Ktor前端DeviseJWT认证实现求助
解决Devise JWT认证的Ktor前端问题
一、实现Ktor中类似Fetch API credentials: include 的Cookie保存逻辑
Kotlin/JS的Ktor要处理跨域Cookie,需在请求配置中开启凭证包含,并配合后端CORS设置:
- 配置Ktor HttpClient,启用Cookie存储并在请求中指定凭证规则:
val client = HttpClient { install(HttpCookies) { storage = AcceptAllCookiesStorage() // 自动存储所有Cookie } install(ContentNegotiation) { json() } } // 登录请求示例 val response = client.post("http://your-rails-api.com/users/sign_in") { contentType(ContentType.Application.Json) setBody(mapOf("user" to mapOf("email" to "test@example.com", "password" to "password123"))) // 对应Fetch的credentials: include,允许携带和接收Cookie credentials(HttpCredentials.Include) } - Rails后端必须配置CORS允许凭证:
修改config/initializers/cors.rb,确保开启credentials: true并指定前端域名:Rails.application.config.middleware.insert_before 0, Rack::Cors do allow do origins 'http://your-ktor-frontend-domain.com' # 替换为实际前端域名 resource '*', headers: :any, methods: [:get, :post, :put, :patch, :delete, :options, :head], credentials: true end end - 补充Devise JWT的Cookie存储配置(若用Cookie存token):
在config/initializers/devise.rb中添加:config.jwt do |jwt| jwt.token_store = :cookie jwt.cookie_options = { secure: Rails.env.production?, httponly: true, same_site: :lax } # 保留原有dispatch_requests、revocation_requests、secret_key配置 end
二、通过返回体传递JWT Token的实现方式
虽然这种方式存在XSS风险,但具体实现如下:
Rails后端修改
- 自定义会话控制器,将JWT Token写入响应体:
- 生成控制器文件:
rails generate controller sessions - 编写控制器逻辑,继承Devise SessionsController:
class SessionsController < Devise::SessionsController def create super do |resource| # 生成JWT Token token = Warden::JWTAuth::UserEncoder.new.call(resource, :user, nil).first # 将token放入响应JSON render json: { user: resource, jwt_token: token }, status: :ok and return end end end - 替换Devise默认路由:
在config/routes.rb中修改:devise_for :users, controllers: { sessions: 'sessions' }
- 生成控制器文件:
Ktor前端处理
- 提取响应体中的token并存储,后续请求携带:
data class LoginResponse(val user: User, val jwt_token: String) // 登录请求 val response = client.post<LoginResponse>("http://your-rails-api.com/users/sign_in") { contentType(ContentType.Application.Json) setBody(mapOf("user" to mapOf("email" to "test@example.com", "password" to "password123"))) } // 存储token到localStorage window.localStorage.setItem("jwt_token", response.jwt_token) // 后续接口请求携带token val protectedResponse = client.get("http://your-rails-api.com/protected_resource") { headers { append(HttpHeaders.Authorization, "Bearer ${window.localStorage.getItem("jwt_token")}") } }
内容的提问来源于stack exchange,提问作者H Zaman
相关产品推荐
相关产品推荐

