Fork me on GitHub

Guardian (Βασικά)

Guardian is a widely used authentication library based on JWT (Javascript Web Token).
Η Guardian είναι μια ευρέως διαδεδομένη βιβλιοθήκη πιστοποίησης βασισμένη στο JWT (Javascript Web Token).

Πίνακας περιεχομένων

JWT

Ένα JWT μπορεί να παρέχει ένα πλούσιο κέρμα για πιστοποίηση. Εκεί που πολλά συστήματα πιστοποίησης παρέχουν πρόσβαση μόνο σε ένα αναγνωριστικό αντικειμένου για τον πόρο, τα JWT παρέχουν αυτό μαζί με άλλες πληροφορίες όπως:

Επιπρόσθετα σε αυτά τα πεδία η Guardian παρέχει μερικά άλλα πεδία για να διευκολύνει επιπρόσθετες λειτουργίες:

Αυτά είναι μόνο τα βασικά πεδία σε ένα JWT. Έχετε τη δυνατότητα να προσθέσετε επιπρόσθετες πληροφορίες που χρειάζεται η εφαρμογή σας. Να θυμάστε μόνο να διατηρείτε τη συντομία τους, καθώς το JWT πρέπει να τις προσθέτει στην κεφαλίδα HTTP.

Αυτός ο πλουραλισμός σημαίνει ότι μπορείτε να μεταφέρετε JWT στο σύστημά σας σαν ένα πλήρες σύστημα πιστοποιητικών.

Που να τα χρησιμοποιείτε

Τα JWT κέρματα μπορούν να χρησιμοποιηθούν για την πιστοποιήση οποιουδήποτε μέρους της εφαρμογής σας.

Τα κέρματα JWT μπορούν να χρησιμοποιηθούν οπουδήποτε στην εφαρμογή σας χρειάζεται να παρέχετε εξακριβωμένη πιστοποίηση.

Χρειάζεται να χρησιμοποιήσω βάση δεδομένων;

Δεν χρειάζεται να παρακολουθείτε τα JWT με μια βάση δεδομένων. Μπορείτε απλά να στηριχθείτε στις χρονοσημάνσεις έκδοσης και λήξης για να χειριστείτε την πρόσβαση. Συχνά θα καταλήξετε να χρησιμοποιείτε βάση δεδομένων για να βρείτε τον πόρο χρήστη αλλά το ίδιο το JWT δεν το απαιτεί.

Για παράδειγμα, αν έπρεπε να χρησιμοποιήσετε ένα JWT για να πιστοποιήσετε την επικοινωνία σε μια υποδοχή (socket) UDP πιθανότατα δεν θα χρησιμοποιούσατε μια βάση δεδομένων. Κωδικοποιήστε όλες τις πληροφορίες που χρειάζεστε απευθείας στο κέρμα όταν το εκδώσετε. Όταν το επικυρώσετε (ελέγξτε ότι έχει υπογραφεί σωστά) είστε καλυμμένοι.

Μπορείτε πάντως να χρησιμοποιήσετε μια βάση δεδομένων για να παρακολουθήσετε ένα JWT. Αν το κάνετε, αποκτάτε την ικανότητα να επικυρώνετε ότι το κέρμα είναι ακόμα έγκυρο - δηλαδή - ότι δεν έχει ανακαλεστεί. Η θα μπορούσατε να χρησιμοποιήσετε τις εγγραφές στη βάση δεδομένων για να εξαναγκάσετε μια έξοδο όλων των κερμάτων για το χρήστη 5. Αυτό γίνεται εύκολο στην Guardian με τη χρήση της GuardianDb. Η GuardiadDb χρησιμοποιεί τα ‘Hooks’ της Guardian για να κάνει ελέγχους επικύρωσης, να αποθηκεύσει και να διαγράψει από τη βάση δεδομένων. Θα το δούμε αυτό αργότερα.

Μπορώ να χρησιμοποιήσω το κέρμα κάποιου άλλου;

Υπάρχει συχνά η απορία αν είναι σωστό να χρησιμοποιούμε ένα κέρμα OAuth από την Facebook ή την Google σαν κέρμα πιστοποιήσης. Δεν είναι. Η συμπεριφορά αυτών των κερμάτων και η εγκυρότητά τους καθορίζονται εκτός της εφαρμογής σας. Υπάρχει ένας λόγος που βασίζεται περισσότερο στην ασφάλεια όμως. Οποιοσδήποτε αποκτήσει πρόσβαση σε αυτό το κέρμα έχει όχι μόνο πρόσβαση στο site σας, αλλά και στην αντίστοιχή υπηρεσία της Facebook/Google/Κάποιας Άλλης.

Πάντα να χρησιμοποιείτε τα δικά σας κέρματα, τα κέρματα άλλων εφαρμογών είναι χρήσιμα στην ταυτοποίηση κάποιου και στην δημιουργία αιτήσεων προς τα άλλα συστήματα.

Εγκατάσταση

Υπάρχουν πολλές επιλογές για την εγκατάσταση της Guardian. Θα τους δούμε όλους κάποια στιγμή αλλά ας ξεκινήσουμε με μια απλή εγκατάσταση.

Μινιμαλιστική Εγκατάσταση

Για να ξεκινήσετε υπάρχει μια πλειάδα πραγμάτων που θα χρειαστείτε.

Ρυθμίσεις

mix.exs

def application do
  [
    mod: {MyApp, []},
    applications: [:guardian, ...]
  ]
end

def deps do
  [
    {guardian: "~> x.x"},
    ...
  ]
end

config/config.ex

config :guardian, Guardian,
  issuer: "MyAppId",
  secret_key: Mix.env, # σε κάθε αρχείο ρυθμίσεων περιβάλλοντος θα πρέπει να το αντικαταστήσετε αυτό αν είναι εξωτερικό
  serializer: MyApp.GuardianSerializer

Αυτό είναι το ελάχιστο σετ πληροφοριών που χρειάζεται να δώσετε στην Guardian για να λειτουργήσει. Δεν θα πρέπει να κωδικοποιήσετε το μυστικό κλειδί σας κατευθείαν στο αρχείο ρυθμίσεων κορυφαίου επιπέδου. Αντίθετα, κάθε περιβάλλον πρέπει να έχει το δικό του κλειδί. Είναι συχνό να χρησιμοποιείτε την Mix.env για μυστικά κλειδιά στα περιβάλλοντα dev και test. Στα Staging και Production όμως, πρέπει να χρησιμοποιείτε μυστικά κλειδιά που έχουν παραχθεί με την mix phoenix.gen.secret.

lib/my_app/guardian_serializer.ex

defmodule MyApp.GuardianSerializer do
  @behaviour Guardian.Serializer

  alias MyApp.Repo
  alias MyApp.User

  def for_token(user = %User{}), do: { :ok, "User:#{user.id}" }
  def for_token(_), do: { :error, "Unknown resource type" }

  def from_token("User:" <> id), do: { :ok, Repo.get(User, id) }
  def from_token(_), do: { :error, "Unknown resource type" }
end

Ο serializer σας είναι υπέυθυνος για την έυρεση της πηγής που ορίζεται στο πεδίο sub (υποκείμενο). Αυτό θα μπορεί να είναι μια αναζήτηση στη βάση δεδομένων, ένα API, ή ακόμα ένα απλό αλφαριθμητικό.
Είναι επίσης υπεύθυνος για την γραμμικοποίηση ενός πόρου στο πεδίο sub.

Αυτό ήταν όλο για την ελάχιστη ρύθμιση. Υπάρχουν πολλά ακόμα που μπορείτε να κάνετε, αν τα χρειάζεστε, αλλά αυτά αρκούν για να ξεκινήσετε.

Χρήση Εφαρμογής

Τώρα που έχουμε τις ρυθμίσεις στη θέση τους για να χρησιμοποιήσουμε την Guardian, πρέπει να την ενσωματώσουμε στην εφαρμογή μας. Από τη στιγμή που αυτή είναι η ελάχιστη ρύθμιση, ας αναλογιστούμε πρώτα τις αιτήσεις HTTP.

Αιτήσεις HTTP

Η Guardian παρέχει ένα σύνολο Plugs για να διευκολύνει την ενσωμάτωση σε αιτήσεις HTTP. Μπορείτε να μάθετε για το Plug σε ένα άλλο μάθημα. Η Guardian δεν χρειάζεται την Phoenix, αλλά η χρήση της Phoenix κάνει ευκολότερη την παρουσίαση των ακόλουθων παραδειγμάτων.

Ο πιο εύκολος τρόπος να ενσωματώσετε στο HTTP είναι μέσω του δρομολογητή (router). Από τη στιγμή που οι ενσωματώσεις της Guardian στο HTTP είναι όλες βασισμένες σε plugs, μπορείτε να τις χρησιμοποιήσετε οπουδήποτε μπορεί να χρησιμοποιηθεί ένα plug.

Η γενική ροή ενός plug της Guardian είναι:

  1. Εύρεση ενός κέρματος στην αίτηση (κάπου) και επικύρωσή του: ‘Verify*’ plugs
  2. Προεραιτικά φορτώσή του πόρου που ορίζεται στο κέρμα: LoadResource plug
  3. Βεβαίωση ότι υπάρχει ένα έγκυρο κέρμα για την αίτηση και αρνήση πρόσβασης αν όχι. EnsureAuthenticated plug

Για να καλυφθούν όλες οι ανάγκες των προγραμματιστών εφαρμογών, η Guardian υλοποιεί αυτές τις φάσεις ξεχωριστά. Για να βρείτε το κέρμα χρησιμοποιείστε τα plugs Verify*.

Ας δημιουργήσουμε μερικούς αγωγούς.

pipeline :maybe_browser_auth do
  plug Guardian.Plug.VerifySession
  plug Guardian.Plug.VerifyHeader, realm: "Bearer"
  plug Guardian.Plug.LoadResource
end

pipeline :ensure_authed_acces do
  plug Guardian.Plug.EnsureAuthenticated, %{"typ" => "access", handler: MyApp.HttpErrorHandler}
end

Αυτοί οι αγωγοί μπορούν να χρησιμοποιηθούν για να συνθέσουν διαφορετικές απαιτήσεις πιστοποίησης. Ο πρώτος αγωγός προσπαθεί να βρει ένα κέρμα πρώτα στη συνεδρία και στη συνέχεια οπισθοχωρεί σε μια κεφαλίδα. Αν βρει ένα, τότε σας φορτώνει τον πόρο.

Ο δεύτερος αγωγός απαιτεί ότι υπάρχει ένα έγκυρο, επικυρωμένο κέρμα και ότι είναι τύπου “access”. Για να τα χρησιμοποιήσετε, προσθέστε τα στο πεδίο δράσης σας.

scope "/", MyApp do
  pipe_through [:browser, :maybe_browser_auth]
  
  get "/login", LoginController, :new
  post "/login", LoginController, :create
  delete "/login", LoginController, :delete
end

scope "/", MyApp do
  pipe_through [:browser, :maybe_browser_auth, :ensure_authed_access]
  
  resource "/protected/things", ProtectedController
end

Οι δρομολογητές εισόδου παραπάνω θα έχουν τον πιστοποιημένο χρήστη αν υπάρχει. Το δεύτερο πεδίο δράσης βεβαιώνει ότι ένα έγκυρο κέρμα περνάει σε όλες τις λειτουργίες.
Δεν χρειάζεται να τις βάλετε στους αγωγούς, θα μπορούσατε να τις βάλετε στους controlllers σας για περισσότερο ευλύγιστη παραμετροποίηση αλλά εδώ φτάχνουμε μια μινιμαλιστική εγκατάσταση.

Μας λείπει ένα κομμάτι ως τώρα. Ο χειριστής σφαλμάτων που προσθέσαμε στο plug EnsureAuthenticated. Αυτή είναι μια πολύ απλή ενότητα που απαντάει στα

Και οι δύο αυτές συναρτήσεις λαμβάνουν μια δομή Plug.Conn και ένα χάρτη παραμέτρων και θα πρέπει να χειριστούν τα επιμέρους σφάλματά τους. Μπορείτε ακόμα να χρησιμοποιήσετε έναν Phoenix controller!

Στον controller

Μέσα στον controller, υπάρχουν μερικές επιλογές για το πως θα έχετε πρόσβαση στον τρέχοντα εισηγμένο χρήστη. Ας αρχίσουμε με τον απλούστερο.

defmodule MyApp.MyController do
  use MyApp.Web, :controller
  use Guardian.Phoenix.Controller
  
  def some_action(conn, params, user, claims) do
    # Κάντε διάφορα
  end
end

Χρησιμοποιώντας την ενότητα Guardian.Phoenix.Controller, οι λειτουργίες σας θα λαμβάνουν δύο περαιτέρω ορίσματα στα οποία μπορείτε να αντιπαραβληθείτε. Θυμηθείτε, αν δεν βεβαιωθήκατε για την πιστοποίηση μπορεί να έχετε έναν κενό χρήστη και αξιώσεις.

Η άλλη - η περισσότερο ευέλικτη έκδοση - είναι να χρησιμοποιήσετε τις βοηθητικές plugs της Guardian.

defmodule MyApp.MyController do
  use MyApp.Web, :controller
  
  def some_action(conn, params) do
    if Guardian.Plug.authenticated?(conn) do
      user = Guardian.Plug.current_resource(conn)
    else
      # Κανένας χρήστης
    end
  end
end

Είσοδος/Έξοδος

Η είσοδος και η έξοδος μιας συνόδου browser είναι πολύ απλή. Στον controller εισόδου σας:

def create(conn, params) do
  case find_the_user_and_verify_them_from_params(params) do
    {:ok, user} ->
      conn
      |> Guardian.Plug.sign_in(user, :access) # Χρησιμοποιήστε κέρματα πρόσβασης. Άλλα κέρματα μπορούν να χρησιμοποιηθούν, όπως τα :refrech κ.α.
      |> respond_somehow()
    {:error, reason} ->
      # χειριστείτε την μη επικύρωση των διαπιστευτηρίων του χρήστη.
  end
end

def delete(conn, params) do
  conn
  |> Guardian.Plug.sign_out()
  |> respond_somehow()
end

Όταν χρησιμοποιείτε το API εισόδου, είναι ελαφρώς διαφορετικό καθώς δεν υπάρχει σύνοδος και πρέπει να παρέχετε το μη επεξεργασμένο κέρμα πίσω στον πελάτη.
Για είσοδο API μάλλον θα χρησιμοποιείτε την κεφαλίδα Authorization για να παρέχετε το κέρμα στην εφαρμογή σας. Αυτή η μέθοδος είναι χρήσιμη όταν δεν σκοπέυετε να χρησιμοποιήσετε μια σύνοδο.

def create(conn, params) do
  case find_the_user_and_verify_them_from_params(params) do
    {:ok, user} ->
      {:ok, jwt, _claims} = Guardian.encode_and_sign(user, :access)
      conn
      |> respond_somehow({token: jwt})
    {:error, reason} ->
      # χειριστείτε την μη επικύρωση των διαπιστευτηρίων του χρήστη
  end
end

def delete(conn, params) do
  jwt = Guardian.Plug.current_token(conn)
  Guardian.revoke!(jwt)
  respond_somehow(conn)
end

Η είσοδος συνόδου browser καλεί την encode_and_sign κάτω από το καπώ έτσι μπορείτε να τις χρησιμοποιήσετε με τον ίδιο τρόπο.


Share This Page