Skip to main content
We publish frequent updates to our documentation, and translation of this page may still be in progress. For the most current information, please visit the English documentation.

Diese Version von GitHub Enterprise wird eingestellt am 2023-03-15. Es wird keine Patch-Freigabe vorgenommen, auch nicht für kritische Sicherheitsprobleme. Für bessere Leistung, verbesserte Sicherheit und neue Features aktualisiere auf die neueste Version von GitHub Enterprise. Wende dich an den GitHub Enterprise-Support, um Hilfe zum Upgrade zu erhalten.

Grundlagen der Authentifizierung

Hier erfährst du anhand einiger Beispiele mehr über die verschiedenen Möglichkeiten der Authentifizierung.

In diesem Abschnitt werden die Grundlagen der Authentifizierung beschrieben. Dabei wird (mithilfe von Sinatra) ein Ruby-Server erstellt, der den Webflow einer Anwendung auf unterschiedliche Weise implementiert.

Du kannst den vollständigen Quellcode für dieses Projekt aus dem Repository mit den Plattformbeispielen herunterladen.

Registrieren deiner App

Zunächst musst du Deine Anwendung registrieren. Jeder registrierten OAuth-Anwendung wird eine eindeutige Client-ID und ein geheimer Clientschlüssel zugewiesen. Der geheime Clientschlüssel darf nicht mit anderen geteilt werden! Dies gilt auch für das Einchecken der Zeichenfolge in deinem Repository.

Dabei kannst du mit Ausnahme der Rückruf-URL für die Autorisierung sämtliche Informationen eintragen. Dies ist mit Abstand das wichtigste Element bei der Einrichtung deiner Anwendung. GitHub Enterprise Server leitet Benutzer*innen nach der erfolgreichen Authentifizierung an diese Rückruf-URL.

Da wir einen regulären Sinatra-Server ausführen, wird der Speicherort der lokalen Instanz auf http://127.0.0.1:4567 festgelegt. Hier wird http://127.0.0.1:4567/callback als Rückruf-URL angegeben.

Akzeptieren der Benutzerautorisierung

Veraltungshinweis: GitHub führt die Authentifizierung mit der API mit Abfrageparametern nicht mehr aus. Die Authentifizierung mit der API sollte mit HTTP-Standardauthentifizierung erfolgen. Weitere Informationen (einschließlich geplanter Änderungen) findest du im Blogbeitrag.

Die Authentifizierung bei der API mithilfe von Abfrageparametern (wenn verfügbar) wird aufgrund von Sicherheitsbedenken nicht mehr unterstützt. Stattdessen wird empfohlen, dass Integratoren ihr Zugriffstoken (client_id) oder das client_secret in die Kopfzeile verschieben. GitHub wird die Abschaffung der Authentifizierung durch Abfrageparameter mit einer Vorankündigung ankündigen.

Im nächsten Schritt werden die Serverinformationen angegeben. Erstelle eine Datei server.rb, und füge die folgenden Angaben in diese Datei ein:

require 'sinatra'
require 'rest-client'
require 'json'

CLIENT_ID = ENV['GH_BASIC_CLIENT_ID']
CLIENT_SECRET = ENV['GH_BASIC_SECRET_ID']

get '/' do
  erb :index, :locals => {:client_id => CLIENT_ID}
end

Deine Client-ID und die geheimen Clientschlüssel stammen von der Konfigurationsseite deiner Anwendung. Stattdessen sollten diese Werte wie hier gezeigt als Umgebungsvariablen gespeichert werden.

Füge nun in views/index.erb diesen Inhalt ein:

<html>
  <head>
  </head>
  <body>
    <p>
      Well, hello there!
    </p>
    <p>
      We're going to now talk to the GitHub API. Ready?
      <a href="https://github.com/login/oauth/authorize?scope=user:email&client_id=<%= client_id %>">Click here</a> to begin!
    </p>
    <p>
      If that link doesn't work, remember to provide your own <a href="/apps/building-oauth-apps/authorizing-oauth-apps/">Client ID</a>!
    </p>
  </body>
</html>

(Wenn du nicht mit der Funktionsweise von Sinatra vertraut bist, solltest du den Sinatra-Leitfaden lesen.)

Beachte außerdem, dass die URL den scope-Abfrageparameter verwendet, um die von der Anwendung angeforderten Bereiche zu definieren. Für diese Anwendung wird der Bereich user:email zum Lesen privater E-Mail-Adressen angefordert.

Navigiere in deinem Browser zu http://127.0.0.1:4567. Wenn du auf den Link klickst, solltest du zu GitHub Enterprise Server geleitet werden. Dort sollte ein Dialogfeld angezeigt werden, das dem folgenden ähnelt: GitHub-OAuth-Eingabeaufforderung

Wenn du dir selbst vertraust, klicke auf App autorisieren. Oje! Sinatra gibt einen 404-Fehler aus. Was ist los?

Erinnerst du dich, dass wir als Rückruf-URL callback angegeben haben? Dabei haben wir keine entsprechende Route festgelegt. GitHub Enterprise Server weiß also nicht, wohin Benutzer*innen geleitet werden sollen, nachdem sie die App autorisiert haben. Im Folgenden wird dieses Problem behoben.

Angeben eines Rückrufwerts

Füge in server.rb eine Route für den Rückruf hinzu:

get '/callback' do
  # get temporary GitHub code...
  session_code = request.env['rack.request.query_hash']['code']

  # ... and POST it back to GitHub
  result = RestClient.post('https://github.com/login/oauth/access_token',
                          {:client_id => CLIENT_ID,
                           :client_secret => CLIENT_SECRET,
                           :code => session_code},
                           :accept => :json)

  # extract the token and granted scopes
  access_token = JSON.parse(result)['access_token']
end

Nach einer erfolgreichen App-Authentifizierung stellt GitHub Enterprise Server einen temporären code-Wert bereit. Dieser Code muss per POST an GitHub Enterprise Server zurückgegeben werden und gegen ein Zugriffstoken (access_token) ausgetauscht werden. Zur Vereinfachung dieser GET- und POST-HTTP-Anforderungen verwenden wir rest-client. Beachte, dass du wahrscheinlich niemals über REST auf die API zugreifen wirst. In der Praxis solltest du vermutlich eher eine Bibliothek in deiner bevorzugten Sprache verwenden.

Überprüfen der gewährten Bereiche

Benutzerinnen können die angeforderten Bereiche bearbeiten, indem sie die URL direkt ändern. Dadurch kann deine Anwendung einen geringeren Umfang an Zugriffsberechtigungen erhalten, als du ursprünglich angefordert hattest. Bevor du Anforderungen mit dem Token erstellst, solltest du überprüfen, welche Bereiche der oder dem Benutzerin für das Token gewährt wurden. Weitere Informationen zu angeforderten und gewährten Bereichen findest du unter Scopes for OAuth Apps („Bereiche für OAuth-Apps“).

Die gewährten Bereiche werden beim Austausch eines Tokens als Teil der Antwort zurückgegeben.

get '/callback' do
  # ...
  # Get the access_token using the code sample above
  # ...

  # check if we were granted user:email scope
  scopes = JSON.parse(result)['scope'].split(',')
  has_user_email_scope = scopes.include? 'user:email'
end

In unserer Anwendung wird mithilfe von scopes.include? überprüft, ob der Bereich user:email gewährt wurde, der zum Abrufen der privaten E-Mail-Adressen der authentifizierten Benutzer*innen erforderlich ist. Wenn die Anwendung weitere Bereiche angefordert hätte, hätten wir auch diese Bereiche überprüft.

Da zudem eine hierarchische Beziehung zwischen Bereichen besteht, solltest du überprüfen, ob dir die niedrigste Stufe der erforderlichen Bereiche gewährt wurde. Wenn die Anwendung z. B. den Bereich user angefordert hat, wurde ihr möglicherweise nur der Bereich user:email zugewiesen. In diesem Fall wäre der Anwendung zwar nicht der angeforderte Bereich gewährt worden, der gewährte Bereich wäre jedoch trotzdem ausreichend.

Da Benutzer*innen die Bereiche zwischen deiner Überprüfung und der eigentlichen Anforderung noch ändern können, ist es nicht ausreichend, die Bereiche lediglich vor dem Ausführen von Anforderungen zu überprüfen. Denn bei einer solchen Änderung tritt bei API-Aufrufen, bei denen du eine erfolgreiche Ausführung erwartet hast, möglicherweise ein Fehler mit dem Status 404 bzw. 401 auf, oder du erhältst eine andere Teilmenge an Informationen als erwartet.

Damit diese Situation vermieden wird, enthalten alle API-Antworten auf Anforderungen mit gültigen Token auch einen X-OAuth-Scopes-Header. In diesem Header sind die Bereiche des Tokens aufgeführt, das für die Anforderung verwendet wurde. Darüber hinaus bietet die REST-API einen Endpunkt zum Überprüfen eines Tokens auf Gültigkeit. Verwende diese Informationen, um Änderungen an Tokenbereichen zu ermitteln, und informiere deine Benutzer*innen über Änderungen bei den verfügbaren Anwendungsfunktionen.

Ausführen von authentifizierten Anforderungen

Schließlich kannst du mit diesem Zugriffstoken authentifizierte Anforderungen als angemeldeter Benutzerin vornehmen:

# fetch user information
auth_result = JSON.parse(RestClient.get('http(s)://HOSTNAME/api/v3/user',
                                        {:params => {:access_token => access_token}}))

# if the user authorized it, fetch private emails
if has_user_email_scope
  auth_result['private_emails'] =
    JSON.parse(RestClient.get('http(s)://HOSTNAME/api/v3/user/emails',
                              {:params => {:access_token => access_token}}))
end

erb :basic, :locals => auth_result

Mit den Ergebnissen kannst du beliebige Schritte ausführen. In diesem Fall setzen wir unsere Arbeit direkt mit basic.erb fort:

<p>Hello, <%= login %>!</p>
<p>
  <% if !email.nil? && !email.empty? %> It looks like your public email address is <%= email %>.
  <% else %> It looks like you don't have a public email. That's cool.
  <% end %>
</p>
<p>
  <% if defined? private_emails %>
  With your permission, we were also able to dig up your private email addresses:
  <%= private_emails.map{ |private_email_address| private_email_address["email"] }.join(', ') %>
  <% else %>
  Also, you're a bit secretive about your private email addresses.
  <% end %>
</p>

Implementieren einer „persistenten“ Authentifizierung

Es wäre sehr ungünstig, wenn Benutzer*innen sich jedes Mal bei der App anmelden müssten, wenn sie auf die Webseite zugreifen möchten. Versuche z. B., direkt zu http://127.0.0.1:4567/basic zu navigieren. Du erhältst eine Fehlermeldung.

Was wäre, wenn der gesamte „Hier klicken“-Vorgang umgangen werden könnte? Und stattdessen einfach festgelegt_ wird, dass Benutzer*innen auf die Anwendung zugreifen können sollen, solange sie bei GitHub Enterprise Server angemeldet sind? _Genau das werden wir jetzt umsetzen.

Unser kleiner Server oben ist ein ziemlich einfaches Beispiel. Für einen intelligenten Authentifizierungsprozess verwenden wir nun Sitzungen, um Token zu speichern. Dadurch wird die Authentifizierung für Benutzer*innen transparent.

Da die Bereiche innerhalb der Sitzung beibehalten werden, muss zudem eine Vorgehensweise für Situationen definiert werden, in denen Benutzerinnen die Bereiche nach der Überprüfung aktualisieren oder das Token widerrufen. Dazu wird ein rescue-Block verwendet, und es wird überprüft, ob der erste API-Aufruf erfolgreich ist. Dadurch wird sichergestellt, dass das Token noch gültig ist. Danach wird anhand des X-OAuth-Scopes-Antwortheaders überprüft, ob der user:email-Bereich durch die oder den Benutzerin widerrufen wurde.

Erstelle eine Datei advanced_server.rb, und füge diese Zeilen in der Datei ein:

require 'sinatra'
require 'rest_client'
require 'json'

# !!! DO NOT EVER USE HARD-CODED VALUES IN A REAL APP !!!
# Instead, set and test environment variables, like below
# if ENV['GITHUB_CLIENT_ID'] && ENV['GITHUB_CLIENT_SECRET']
#  CLIENT_ID        = ENV['GITHUB_CLIENT_ID']
#  CLIENT_SECRET    = ENV['GITHUB_CLIENT_SECRET']
# end

CLIENT_ID = ENV['GH_BASIC_CLIENT_ID']
CLIENT_SECRET = ENV['GH_BASIC_SECRET_ID']

use Rack::Session::Pool, :cookie_only => false

def authenticated?
  session[:access_token]
end

def authenticate!
  erb :index, :locals => {:client_id => CLIENT_ID}
end

get '/' do
  if !authenticated?
    authenticate!
  else
    access_token = session[:access_token]
    scopes = []

    begin
      auth_result = RestClient.get('http(s)://HOSTNAME/api/v3/user',
                                   {:params => {:access_token => access_token},
                                    :accept => :json})
    rescue => e
      # request didn't succeed because the token was revoked so we
      # invalidate the token stored in the session and render the
      # index page so that the user can start the OAuth flow again

      session[:access_token] = nil
      return authenticate!
    end

    # the request succeeded, so we check the list of current scopes
    if auth_result.headers.include? :x_oauth_scopes
      scopes = auth_result.headers[:x_oauth_scopes].split(', ')
    end

    auth_result = JSON.parse(auth_result)

    if scopes.include? 'user:email'
      auth_result['private_emails'] =
        JSON.parse(RestClient.get('http(s)://HOSTNAME/api/v3/user/emails',
                       {:params => {:access_token => access_token},
                        :accept => :json}))
    end

    erb :advanced, :locals => auth_result
  end
end

get '/callback' do
  session_code = request.env['rack.request.query_hash']['code']

  result = RestClient.post('https://github.com/login/oauth/access_token',
                          {:client_id => CLIENT_ID,
                           :client_secret => CLIENT_SECRET,
                           :code => session_code},
                           :accept => :json)

  session[:access_token] = JSON.parse(result)['access_token']

  redirect '/'
end

Der Code sollte Ihnen im Wesentlichen vertraut erscheinen. Es wird z. B. weiterhin RestClient.get für den Aufruf der GitHub Enterprise Server-API verwendet, und die Ergebnisse werden wie zuvor für die Anzeige in einer ERB-Vorlage (in diesem Fall advanced.erb) übergeben.

Außerdem wird nun mithilfe der authenticated?-Methode überprüft, ob die oder der Benutzer*in bereits authentifiziert ist. Falls nicht, wird die Methode authenticate! aufgerufen, mit der der OAuth-Flow ausgeführt und die Sitzung mit den gewährten Bereichen und Token aktualisiert wird.

Als Nächstes erstellst du in views die Datei advanced.erb und fügst dieses Markup ein:

<html>
  <head>
  </head>
  <body>
    <p>Well, well, well, <%= login %>!</p>
    <p>
      <% if !email.empty? %> It looks like your public email address is <%= email %>.
      <% else %> It looks like you don't have a public email. That's cool.
      <% end %>
    </p>
    <p>
      <% if defined? private_emails %>
      With your permission, we were also able to dig up your private email addresses:
      <%= private_emails.map{ |private_email_address| private_email_address["email"] }.join(', ') %>
      <% else %>
      Also, you're a bit secretive about your private email addresses.
      <% end %>
    </p>
  </body>
</html>

Rufe an der Befehlszeile ruby advanced_server.rb auf, um deinen Server an Port 4567 zu starten. Dies ist derselbe Port, den wir bereits bei der einfachen Sinatra-App verwendet haben. Wenn du zu http://127.0.0.1:4567 navigierst, ruft die App authenticate! auf, um dich zu /callback umzuleiten. /callback leitet dich dann erneut zu / und zeigt advanced.erb an, da du bereits authentifiziert wurdest.

Dieses Roundtriprouting könnte erheblich vereinfacht werden, indem die Rückruf-URL in GitHub Enterprise Server ganz einfach in / geändert wird. Da server.rb und advanced.rb dieselbe Rückruf-URL verwenden, sind diese zusätzlichen Schritte jedoch erforderlich.

Wäre diese Anwendung zudem niemals für den Zugriff auf die GitHub Enterprise Server-Daten autorisiert worden, wäre als Warnhinweis dasselbe Bestätigungsdialogfeld angezeigt worden wie zuvor.