最近,我在heroku上部署了Rails后端和Vue前端。几天前一切似乎都很好,直到我今天尝试登录Web应用程序为止。登录后,我立即收到401响应,因为登录后,该应用程序应该显示数据库中的漫画书。
对于背景,我正在通过webcrunch在youtube上关注Vue.js / Rails教程。在本教程中,localStorage与JWTSessions和axios一起使用。我使用了以下问题,但没有提供我正在寻找的HttpGet 401 status code followed by 200 status code答案。我也尝试在我的api网址中添加尾部斜杠,但这不能解决问题。在vue前端中,本教程还使用了axios / index.js文件,该文件配置axios请求的实例。
application_controller.rb
class ApplicationController < ActionController::Base
include JWTSessions::RailsAuthorization
rescue_from JWTSessions::Errors::Unauthorized, with: :not_authorized
private
# access current user
def current_user
@current_user ||= User.find(payload['user_id'])
end
def not_authorized
# render actual data back since no view
render json: { error: 'Not authorized' }, status: :unauthorized
end
end
signin_controller.rb(不包含signup_controller.rb,因为它们相似)
class SigninController < ApplicationController
before_action :authorize_access_request!, only: [:destroy]
skip_before_action :verify_authenticity_token
def create
user = User.find_by!(email: params[:email])
if user.authenticate(params[:password])
payload = { user_id: user.id }
# allow user to log in again if failed attempt
session = JWTSessions::Session.new(payload: payload, refresh_by_access_allowed: true)
tokens = session.login
response.set_cookie(JWTSessions.access_cookie,
value: tokens[:access],
httponly: true,
secure: Rails.env.production?)
render json: { csrf: tokens[:csrf] }
else
not_authorized
end
end
def destroy
session = JWTSessions::Session.new(payload: payload)
session.flush_by_access_payload
render json: :ok
end
private
def not_found
render json: { error: "Cannot find email/password combination" }, status: :not_found
end
end
/config/initializers/cors.rb
Rails.application.config.middleware.insert_before ActionDispatch::Static, Rack::Cors do
allow do
origins ['https://gem-mint-client.herokuapp.com', 'http://gem-mint-client.herokuapp.com']
resource '*',
headers: :any,
credentials: true,
methods: [:get, :post, :put, :patch, :delete, :options, :head]
end
end
/frontend/src/backend/axios/index.js
import axios from 'axios'
const API_URL = 'https://gem-mint-server.herokuapp.com'
const securedAxiosInstance = axios.create({
baseURL: API_URL,
withCredentials: true,
headers: {
'Content-Type': 'application/json'
}
})
const plainAxiosInstance = axios.create({
baseURL: API_URL,
withCredentials: true,
headers: {
'Content-Type': 'application/json'
}
})
securedAxiosInstance.interceptors.request.use(config => {
const method = config.method.toUpperCase()
if (method !== 'OPTIONS' && method !== 'GET') {
config.headers = {
...config.headers,
'X-CSRF-TOKEN': localStorage.csrf
}
}
return config
})
securedAxiosInstance.interceptors.response.use(null, error => {
if (error.response && error.response.config && error.response.status === 401) {
return plainAxiosInstance.post('/refresh', {}, { headers: { 'X-CSRF-TOKEN': localStorage.csrf } })
.then(response => {
localStorage.csrf = response.data.csrf
localStorage.signedIn = true
let retryConfig = error.response.config
retryConfig.headers['X-CSRF-TOKEN'] = localStorage.csrf
return plainAxiosInstance.request(retryConfig)
}).catch(error => {
delete localStorage.csrf
delete localStorage.signedIn
location.replace('/')
return Promise.reject(error)
})
} else {
return Promise.reject(error)
}
})
export { securedAxiosInstance, plainAxiosInstance }
我当时正在处理CORS问题,但我认为情况并非如此。我的CORS问题是因为我在浏览器标题中输入的URL不带https,因此要解决的问题是我同时将https和http url都包括在内。我期望的最终结果是您应该能够登录或注册,而不会由于未授权而立即注销。如果需要更多代码,请告诉我。预先谢谢你。
Edit2:comics_controller.rb
module Api
module V1
class ComicsController < ApplicationController
before_action :authorize_access_request!
before_action :set_comic, only: [:show, :edit, :update, :destroy]
skip_before_action :verify_authenticity_token
# GET /comics
# GET /comics.json
def index
@comics = current_user.comics.all
render json: @comics
end
# GET /comics/marvel
def marvel
# start connection to Marvel
@client = Marvel::Client.new
# keys to configure marvel api
@client.configure do |config|
config.api_key = ENV['PUBLIC_MARVEL_API']
config.private_key = ENV['PRIVATE_MARVEL_API']
end
# store parameters to send as request
# set limit to 100, otherwise server error if over
@args = {limit: '100'}
# marvel api creator parameter needs to be inputted as an id
# find creator id
if params[:creators] != ''
@creator = @client.creators(nameStartsWith: params[:creators])
@args[:creators] = @creator[0][:id]
end
# check if other params were inputted and add to @args object
if params[:issueNumber] != ''
@args[:issueNumber] = params[:issueNumber]
end
if params[:title] != ''
@args[:titleStartsWith] = params[:title]
end
if params[:startYear] != ''
@args[:startYear] = params[:startYear]
end
# find comics based on given parameters
@comics = @client.comics(@args)
render json: @comics
end
# GET /comics/price
def price
EbayRequest.configure do |config|
config.appid = ENV['EBAY_APP_PROD_ID']
config.certid = ENV['EBAY_CERT_PROD_ID']
config.devid = ENV['EBAY_DEV_PROD_ID']
config.runame = ENV['EBAY_PROD_RUNAME']
config.sandbox = false
end
@items = EbayRequest::Finding.new.response('findItemsAdvanced', categoryId: '63', keywords: params[:query])
render json: @items
end
# GET /comics/1
# GET /comics/1.json
def show
@comic
render json: @comic
end
# GET /comics/new
def new
@comic = Comic.new
end
# GET /comics/1/edit
def edit
end
# POST /comics
# POST /comics.json
def create
@comic = current_user.comics.build(comic_params)
respond_to do |format|
if current_user.comics.exists?(title: @comic.title)
# access first object
found_book = current_user.comics.where(title: @comic.title)[0]
quantity = found_book.quantity
# sum up previous quantity with additional quantity
found_book.update_attribute(:quantity, quantity + @comic.quantity)
format.html { redirect_to '/', notice: 'Invite was successfully created' }
format.json {
render json: @comic, status: :created, location: api_v1_comic_url(@comic)
}
else
# if no records exist, create a new one
if @comic.save
format.html { redirect_to '/', notice: 'Invite was successfully created' }
format.json {
render json: @comic, status: :created, location: api_v1_comic_url(@comic)
}
else
format.html { render :new }
format.json {
render json: @comic.errors, status: :unprocessable_entity
}
end
end
end
end
# PATCH/PUT /comics/1
# PATCH/PUT /comics/1.json
def update
respond_to do |format|
if @comic.update(comic_params)
format.html
format.json {
render json: @comic, status: :created, location: api_v1_comic_url(@comic)
}
else
format.html { render :new }
format.json {
render json: @comic.errors, status: :unprocessable_entity
}
end
end
end
# DELETE /comics/1
# DELETE /comics/1.json
def destroy
@comic.destroy
end
private
# Use callbacks to share common setup or constraints between actions.
def set_comic
@comic = current_user.comics.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def comic_params
params.require(:comic).permit(:title, :issue, :year, :image, {:creators => []}, :quantity, :description)
end
end
end
end
编辑:日志输出
at=info method=POST path="/signin" host=gem-mint-server.herokuapp.com request_id=a6f30e31-8f19-4c7f-9381-4135efb0f648 fwd="75.18.100.151" dyno=web.1 connect=1ms service=307ms status=200 bytes=1162 protocol=https
2019-08-07T21:15:03.882596+00:00 app[web.1]: I, [2019-08-07T21:15:03.882487 #4] INFO -- : [a6f30e31-8f19-4c7f-9381-4135efb0f648] Completed 200 OK in 303ms (Views: 0.2ms | ActiveRecord: 1.6ms)
2019-08-07T21:15:04.170728+00:00 heroku[router]: at=info method=GET path="/api/v1/comics" host=gem-mint-server.herokuapp.com request_id=3afecf82-2c42-4e2c-9f25-cffeb88b5017 fwd="75.18.100.151" dyno=web.1 connect=1ms service=4ms status=401 bytes=736 protocol=https
2019-08-07T21:15:04.170050+00:00 app[web.1]: I, [2019-08-07T21:15:04.169938 #4] INFO -- : [3afecf82-2c42-4e2c-9f25-cffeb88b5017] Started GET "/api/v1/comics" for 75.18.100.151 at 2019-08-07 21:15:04 +0000
2019-08-07T21:15:04.170902+00:00 app[web.1]: I, [2019-08-07T21:15:04.170835 #4] INFO -- : [3afecf82-2c42-4e2c-9f25-cffeb88b5017] Processing by Api::V1::ComicsController#index as HTML
2019-08-07T21:15:04.171594+00:00 app[web.1]: I, [2019-08-07T21:15:04.171528 #4] INFO -- : [3afecf82-2c42-4e2c-9f25-cffeb88b5017] Completed 401 Unauthorized in 1ms (Views: 0.2ms | ActiveRecord: 0.0ms)
2019-08-07T21:15:04.373727+00:00 app[web.1]: I, [2019-08-07T21:15:04.373626 #4] INFO -- : [82467937-7dbc-4cf2-9cf1-c010f92fad41] Started POST "/refresh" for 75.18.100.151 at 2019-08-07 21:15:04 +0000
2019-08-07T21:15:04.374995+00:00 app[web.1]: I, [2019-08-07T21:15:04.374936 #4] INFO -- : [82467937-7dbc-4cf2-9cf1-c010f92fad41] Processing by RefreshController#create as HTML
2019-08-07T21:15:04.375091+00:00 app[web.1]: I, [2019-08-07T21:15:04.375032 #4] INFO -- : [82467937-7dbc-4cf2-9cf1-c010f92fad41] Parameters: {"refresh"=>{}}
2019-08-07T21:15:04.376098+00:00 app[web.1]: I, [2019-08-07T21:15:04.376018 #4] INFO -- : [82467937-7dbc-4cf2-9cf1-c010f92fad41] Completed 401 Unauthorized in 1ms (Views: 0.3ms | ActiveRecord: 0.0ms)