Rails를 사용한 Pokedex 섹션 2 구축 - 인증

22286 단어 railsruby
안녕하세요, 여러분!작년에 우리는 Pokedex API의 대부분 설정을 완성했는데 데이터베이스 구축, 모델 생성, 컨트롤러, 서열화 프로그램과 루트, 검증을 추가하고 데이터베이스에 예시를 심었다.이 라운드에서 우리는 세션과 쿠키를 사용하는 사용자를 위해 인증을 설정할 것입니다.
현재 세션과 쿠키를 사용해서 JSON 웹 영패(JWT)와 신분 검증을 해야 하는지에 대한 논쟁이 많은데 그 중 많은 것이 응용 프로그램이 무엇을 하기를 원하는지와 관련이 있습니다.둘 다 위험이 있습니다. 로컬 저장소를 JWT와 함께 사용하면 크로스 사이트 스크립트 (XSS) 공격을 받기 쉽고, 세션과 쿠키는 크로스 사이트 위조 요청 (CSRF) 에 약할 수 있습니다.이 두 가지 상황에서 모두 위험을 최소화하는 데 도움을 줄 방법이 있다.이것blog은 더욱 깊은 토론을 제공하고 또 다른 신분 검증을 실현하는 방식을 보여 주었다. 이것은 내가 여기서 여러분에게 보여줄 방식과 다르다.
제가 세션과 쿠키를 사용하는 이유는 제 경험에 따라 더욱 쉽게 이루어질 수 있고 우리가 합작하고 있는 Pokedex project API에 요청을 보낼 준비가 되어 있을 때 전방에서 해야 할 일이 더 적기 때문입니다.
자, 우리 파티를 시작합시다!
pokedexapi/config/initializers/cors에 있습니다.rb 우리는 받아들일 수 있는 방법 후에 자원 부분에 증거를 추가해야 한다:true.이것은 쿠키를 사용하여 요청을 보낼 수 있음을 나타낸다.
pokedexapi/config/initializers/cors.rb
Rails.application.config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins 'http://localhost:3000', 'http://localhost:3001', 'http://localhost:3002'

    resource '*',
      headers: :any,
      methods: [:get, :post, :put, :patch, :delete, :options, :head],
      credentials: true
    end
end
rails new를 사용하여 프로그램을 시작할 때 flag-api를 사용했기 때문에 세션과 쿠키 중간부품을 설정하지 않았습니다.그래서 저희가 보충을 해야 돼요.
    config.middleware.use ActionDispatch::Cookies
    config.middleware.use ActionDispatch::Session::CookieStore, key: '_cookie_name'
응용 프로그램.폴더의 rb를 설정합니다.
pokedexapi/config/application.rb
require_relative 'boot'

require "rails"

...

module PokedexApi
  class Application < Rails::Application
    # Initialize configuration defaults for originally generated Rails version.
    config.load_defaults 6.0

    # Settings in config/environments/* take precedence over those specified here.
    # Application configuration can go into files in config/initializers
    # -- all .rb files in that directory are automatically loaded after loading
    # the framework and any gems in your application.

    # Only loads a smaller set of middleware suitable for API only apps.
    # Middleware like session, flash, cookies can be added back manually.
    # Skip views, helpers and assets when generating a new resource.
    config.api_only = true
    config.middleware.use ActionDispatch::Cookies
    config.middleware.use ActionDispatch::Session::CookieStore, key: '_cookie_name'
  end
end
마지막으로 생성된 Application Controller는 하위 클래스인 Action Controller::API를 쿠키 기능이 포함되지 않기 때문에 저희도 추가해야 합니다.
pokedex api/app/controllers/application_controller.rb
class ApplicationController < ActionController::API
  include ::ActionController::Cookies

end
이 설정을 설정하면 우리는 단점을 구축하고 사용자가 필요로 하는 논리를 검증하기 시작할 수 있습니다!
우리가 사용하고자 하는 단점의 이름을 만들기 위해 우리의 루트로 이동합니다.
구성/라우팅rb
Rails.application.routes.draw do

  post "/api/v1/login", to: "api/v1/sessions#create"
  post "/api/v1/signup", to: "api/v1/users#create"
  delete "/api/v1/logout", to: "api/v1/sessions#destroy"
  get "/api/v1/get_current_user", to: "api/v1/sessions#get_current_user"

  namespace :api do 
    namespace :v1 do 
      resources :pokemons
      resources :users
    end
  end
  # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end
참고: 이름 공간의 API와 v1에 수동으로 구축된 라우팅을 다른 사용자처럼 중첩할 수는 없습니다.반복적인 실험을 통해, 만약에api/v1 이름 공간에 끼워 넣으면, 루트를
get "/get_current_user", to: "/sessions#get_current_user"
경로 이름에 api/v1이 추가되지 않았습니다. 여기서 볼 수 있습니다.

, 를 포함하면 두 번 추가됩니다.수수께끼 하나만 맞혀줘!
주의: 로그인, 로그아웃, 현재 사용자 가져오기를 처리하는 SessionController를 만들기 위해 디자인 선택을 했습니다.너는 이 모든 것을 사용자에게 저장할 수 있지만, 나는 이런 방식으로 나의 걱정을 분리하는 것을 좋아한다.사용자 작성은 사용자와 연관된 작업이므로 등록은 UserController로 이동합니다.
현재 $railsss로 rails 서버를 시작하고 http://localhost:3000/api/v1/get_current_user 내비게이션을 하면 초기화되지 않은 상수인SessionController가 존재한다는 오류가 발생합니다. 이것은 우리가 그것을 구축하지 않았기 때문입니다.그러나 현재 중요한 부분은 아래로 스크롤하여 우리가 예상한 대로 노선이 되는지 확인하는 것이다.

그것들은 api/v1에 끼워 넣은 모든 내용을 처리합니다.
이제 다음 명령을 사용하여 SessionController를 만들 수 있습니다.$ rails g controller sessions그것은 우리의 세션 컨트롤러가 될 것이다.계속해서 api/v1로 이동하고 이름 공간을 추가합니다.
app/controllers/api/v1/sessions\u controller.rb
class Api::V1::SessionsController < ApplicationController
end
따라서 생성 작업을 사용하여 SessionController의 한 사용자에 로그인합니다. 이것은 라우트에서 지정한 것입니다.
app/controllers/api/v1/sessions\u controller.rb
class Api::V1::SessionsController < ApplicationController
  def create 
    user = User.find_by(username: params[:session][:username])

    if user && user.authenticate(params[:session][:password])
      session[:user_id] = user.id
      render json: user, status: 200
    else
      render json: {
        error: "Invalid Credentials"
      }
    end
  end
end
여기에서 사용자 set 변수를 만들었습니다. 이 변수는username 파라미터를 사용하여 찾은 사용자 대상입니다. 이 파라미터는sessions 키 아래에 끼워져 있습니다.사용자 이름을 가진 사용자가 있으면 사용자가 입력한 암호가 데이터베이스에 저장된 암호와 일치하는지 확인해야 합니다.인증에 사용되는gem Bcrypt 때문에 암호는 산열과 염분 형식으로 저장되기 때문에 전송된 문자열을 직접 비교할 수 없습니다.그래서 우리는 Bcrypt에서 제공하는 authenticate 방법을 사용해야 한다. 이 방법은params에서 제시한 암호를 암호화하고 산열하며 그 결과가 데이터베이스에서의 암호화와 산열 암호와 일치하는지 확인해야 한다.일치하는 경우 사용자의 고유한 데이터베이스 id인 user id 키를 가진 세션을 생성합니다. 그런 다음 해당 사용자를 JSON 객체로 반환합니다.
만약 신분 검증을 할 수 없다면, 우리는 증빙서류가 무효라는 메시지를 되돌려 주기를 희망합니다.나는 그들에게 이보다 더 많은 정보를 주고 싶지 않다. 만약 우리가 그들에게 사용자 이름이나 비밀번호가 정확하지 않다고 말한다면, 악성 사용자는 사용자 이름과 비밀번호가 그들이 악의적으로 시도한 정보에 대해 더 많은 것을 추측하려고 하기 때문에, 우리는 어떤 방식으로도 그들을 도와주고 싶지 않다.
경험에 의하면, 우리는 세션Controller에서 프런트엔드 요청의 키를 세션 키 밑에 끼워 넣고 싶다는 것을 알고 있습니다.이와 유사:
<ActionController::Parameters {"username"=>"Meks", "password"=>"password", "controller"=>"api/v1/sessions", "action"=>"create", "session"=>{"username"=>"Meks", "password"=>"password"}} permitted: false>
Jordan이 전방에서 우리에게 요청을 보낼 준비가 되었을 때, 우리는 이것에 대해 검증할 것입니다.
일단 사용자가 로그인하면, 만약 그들이 페이지 리셋을 제출한다면, 우리는 그들이 차여서 다시 로그인하는 것을 원하지 않는다.그것은 나쁜 사용자 체험이 될 것이다.따라서 현재 사용자의 세션 id에 따라 현재 사용자를 가져오는 단점을 구축합니다.
app/controllers/api/v1/sessions\u controller.rb
 def get_current_user
    if logged_in?
      render json: current_user, status: 200
    else
      render json: {
        error: "No one logged in"
      }
    end
  end
나는 내가 가지고 싶은 코드를 쓰고 있다.만약 내가 방법이 있다면, 사용자가 로그인했는지 확인할 수 있고, 만약 그들이 로그인한다면, 내가 현재 사용자를 얻을 수 있도록 도와줄 수 있다면, 정말 좋겠다.이것이 바로 나의 get current user 방법에 의존하는 것이다.모든 다른 컨트롤러가 접근할 수 있도록 프로그램 컨트롤러에 그것을 쓰십시오.이것은 현재 사용자가 접근 루트를 허용하거나 실행할 수 있는지 확인함으로써 자원을 보호하는 데 도움을 줄 수 있음을 의미합니다.
app/controllers/api/v1/sessions\u controller.rb
class ApplicationController < ActionController::API
  include ::ActionController::Cookies

  def current_user
    User.find_by(id: session[:user_id])
  end

  def logged_in?
    !!current_user
  end

end
사용자가 로그인할 때 세션을 이 사용자의 id로 설정한 것을 기억하십니까?현재, 우리는 사용자 대상을 되돌려주는 방법을 정의했습니다. 이 사용자 대상의 id는 세션이 가지고 있는 id와 같습니다.로그인하는 방법은 무엇입니까?사용자를 찾으면 부울 값true를 되돌려주고, 찾지 못하면 부울 값false를 되돌려줍니다.사용자가 로그인하지 않으면 세션을 찾을 수 없을 것으로 예상되기 때문입니다.
만약 사용자가 로그인할 수 있다면, 우리는 그들이 로그아웃할 수 있기를 바랍니다.이런 상황을 반영하는 파괴 행위를 적어 봅시다.
app/controllers/api/v1/sessions\u controller.rb
  def destroy
    session.delete :user_id
    if !session[:user_id]
      render json: {
        notice: "successfully logged out"
      }, status: :ok
    else
      render json: {
        error: "Unsuccessful log out"
      }
    end
  end
이 곳에서 세션에서 사용자 id를 삭제하고 이중 검사로 전방에 로그아웃이 성공했다고 알리거나 오류 메시지를 보내면 성공하지 못했다는 것을 알 수 있습니다.다음은 SessionController의 최종 모양입니다.
app/controllers/api/v1/sessions\u controller.rb
class Api::V1::SessionsController < ApplicationController

  def create 
    user = User.find_by(username: params[:session][:username])

    if user && user.authenticate(params[:session][:password])
      session[:user_id] = user.id
      render json: user, status: 200
    else
      render json: {
        error: "Invalid Credentials"
      }
    end
  end

  def get_current_user
    if logged_in?
      render json: current_user, status: 200
    else
      render json: {
        error: "No one logged in"
      }
    end
  end

  def destroy
    session.delete :user_id
    if !session[:user_id]
      render json: {
        notice: "successfully logged out"
      }, status: :ok
    else
      render json: {
        error: "Unsuccessful log out"
      }
    end
  end

end
인증의 수수께끼의 마지막 부분, 등록을 통해 새 사용자를 만듭니다!이 작업은 UsersController의 create 작업에서 수행됩니다.
app/controllers/api/v1/users\u controller.rb
class Api::V1::UsersController < ApplicationController

  def create
    user = User.new(user_params)
    if user.save
      session[:user_id] = user.id
      render json: user, status: 200
    else
      response = {
        error: user.errors.full_messages.to_sentence
      }
      render json: response, status: :unprocessable_entity
    end
  end

  private

  def user_params
    params.permit(:username, :password)
  end

end
여기에서 사용자 매개 변수의 개인적인 방법을 작성하기로 결정했습니다. 그 중에서 사용자 이름과 비밀번호만 매개 변수로 허용합니다.이 사용자 매개 변수는 새 사용자를 만드는 데 사용됩니다. 데이터가 저장되면 세션 [:user id] 을 새로 만든 사용자로 설정합니다. (다시 말하면, 우리는 그들이 등록하는 동시에 로그인합니다.)사용자 객체를 JSON으로 프런트엔드로 보냅니다.만약 사용자가 어떠한 검증 오류로 인해 저장하지 않는다면, 우리는 모든 메시지를 전방으로 보내서 제출이 실패한 원인을 정확하게 알기를 바랍니다.
어떤 인코딩자인지 알아맞혀 보세요. 이것이 바로 신분 검증입니다!다음 번에 최종 단점을 만드는 것을 볼 수 있습니다. 사용자는 포켓몬을 지속적으로 포획하고 포획한 모든 포켓몬을 볼 수 있습니다.우리는 또한 포트가 그녀에게 필요한 데이터를 되돌려 줄 수 있도록 Jordan과 직접 협력할 것이다.
코드를 자세히 보려면 repo을 참조하십시오.
즐거운 코딩!

좋은 웹페이지 즐겨찾기