Nutzer mit sinatra-portier einfachst authentifizieren
Tuesday, 15. November 2016
Sinatra-portier ist ein Fork des Gems sinatra-browserid, das ich ebenfalls vorher geforkt hatte. Es funktioniert für den Entwickler noch genauso, der Unterschied ist, dass statt dem Button ein Formular erstellt wird, und dass Portier zum Bestätigen der Email benutzt wird.
Ein Sinatra-Projekt von Persona auf Portier umstellen
Sinatra-portier ist ganz offiziell als Gem registriert und kann darüber installiert werden:
gem install sinatra-portier
Im Sinatra-Projekt bindet man aber weiterhin sinatra/browserid ein:
require 'sinatra/browserid'
Dadurch kann man ohne Codeanpassung von Persona zu Portier wechseln. In den meisten Projekten muss man nur in der Gemfile gem sinatra-browserid
mit gem sinatra-portier
ersetzen und dann schauen, ob das Loginformular anstatt des Buttons im bestehenden Design ebenfalls funktioniert.
Die API
Es werden einige weniger Helferfunktionen und sinatraweit globale Variablen definiert, mit denen das Gem genutzt wird:
authorized?
True wenn der Nutzer sich mit Portier eingeloggt hat. Die Kernfunktion.
authorized_email
Die Email (als String), mit welcher der Nurzer eingeloggt ist. Kann benutzt werden um die genauen Rechte des Nutzers zu prüfen.
authorize!
Leitet zur Loginseite weiter, wenn der Nutzer nicht bereits eingeloggt ist.
render_login_button
Gibt das HTML des Loginformulars aus.
logout!
Loggt den Nutzer aus,
authorized?
ist danach false undauthorized_email
leer.
Ein Codebeispiel zeigt, wie die Funktionen benutzt werden können:
require 'sinatra/base' require 'sinatra/browserid' module MyApp < Sinatra::Base register Sinatra::BrowserID set :sessions, true get '/' if authorized? "Welcome, #{authorized_email}" else render_login_button end end get '/secure' authorize! # require a user be logged in email = authorized_email # browserid email ... end get '/logout' logout! redirect '/' end end
Nutzungspattern
Mit der obigen API gibt es mehrere Wege, wie man am besten Nutzer anmeldet und ihre Email prüft. Aber ich weiß noch, dass ich eine Weile brauchte um das für mich durchzustrukturieren, trotz des Beispiels. Nicht einfach zu prüfen, ob das eingegebene Passwort das gespeicherte ist, war ungewohnt. Aber im Grunde ist es noch einfacher: Prüfen, ob man die Emailadresse bereits kennt (=ist sie in der Datenbank?) und welche Rechte sie hat.
Ersten Nutzer zum Admin machen
Aber wo fängt man an? Bei der ersten Nutzung ist die Datenbank ja noch leer, es gibt nichts abzugleichen. Meine Projekte, die dieses Gem nutzen (ursprung, feedtragón und music-streamer) zeigen daher einen kleinen Installer, wenn die Datenbank leer ist. In diesem loggt der Nutzer sich über Portier ein, und diese erste Emailadresse wird dann als Adminadresse in der Datenbank gespeichert. Später prüft man, ob authorized_email
die gespeicherte Emailadresse ist, und kann so zu schützende Bereiche der Seite abriegeln.
Weitere Helfer erstellen
Um die Emailadresse auf Adminrechte zu prüfen definiert man am besten zwei weitere Helfer:helpers do def isAdmin? if authorized? if Database.new.getAdminMail == authorized_email return true end end return false end def protected! unless isAdmin? throw(:halt, [401, "Not authorized\n"]) end end end … get %r{/([0-9]+)/editEntry} do |id| protected! … end
Mit Nutzerliste abgleichen
Was aber, wenn man mehr als einen Nutzer haben will? Dann vergleicht man mit der Nutzerdatenbank.helpers do def isAdmin? if authorized? return Database.new.getAdminMail == authorized_email end return false end def isRegistered? if authorized? return Database.new.registered?(authorized_email) end end def protected! unless isRegistered? halt 401, erb(:login) end end def adminProtected! if (isRegistered? && isAdmin?) return true else halt 401, erb(:login) end end endRouten, die normale Nutzer aufrufen können, werden wie zuvor mit
protected!
geschützt. Hier wird nur geschaut, ob in der Datenbank der Nutzer registriert ist. Music-streamer z.B. hat eine Liste in den Einstellungen, in die der Admin neue Adressen und damit neue Nutzer hinzufügen kann. adminProtected!
hingegen prüft, ob authorized_email
die gespeicherte Emailadresse des Admins ist.
Das könnte dann mit einem kompletten Rollensystem erweitert werden, in dem der Code für jede Email prüft, welche Rolle und damit welche Rechte er hat. Und die Datenbankstruktur dafür bleibt simpel:
CREATE TABLE IF NOT EXISTS users( mail TEXT PRIMARY KEY, role TEXT );
Das schöne an dem System ist, was auch bei Persona schon hübsch war: Wir haben mit dem bisschen Code eine komplette Nutzerverwaltung in ein Sinatra-Projekt eingebaut, ohne ein einziges Passwort zu speichern oder auch nur einen Gedanken an Hashverfahren zu verschwenden.
Netz - Rettung - Recht am : Wellenreiten 11/2016
Vorschau anzeigen