Erfahren Sie, wie Sie dem Code für Ihre Web-App eine Anmeldefunktion zur Benutzeranmeldung hinzufügen. Anschließend erfahren Sie, wie Sie auch die Abmeldung ermöglichen.
Anmeldung
Die Anmeldung besteht aus zwei Teilen:
- Schaltfläche für die Anmeldung auf der HTML-Seite
- Anmeldeaktion im CodeBehind im Controller
In ASP.NET Core wird für Microsoft Identity Platform-Anwendungen die Schaltfläche Anmelden in Views\Shared\_LoginPartial.cshtml
(für eine MVC-App) oder Pages\Shared\_LoginPartial.cshtm
(für eine Razor-App) verfügbar gemacht. Sie wird nur angezeigt, wenn der Benutzer sich noch nicht authentifiziert hat. Das heißt, sie wird angezeigt, wenn sich der Benutzer noch nicht angemeldet oder sich zuvor abgemeldet hat. Im Gegensatz dazu wird die Schaltfläche Abmelden angezeigt, wenn der Benutzer bereits angemeldet ist. Beachten Sie, dass der Kontocontroller im NuGet-Paket Microsoft.Identity.Web.UI im Bereich MicrosoftIdentity definiert ist.
<ul class="navbar-nav">
@if (User.Identity.IsAuthenticated)
{
<li class="nav-item">
<span class="navbar-text text-dark">Hello @User.Identity.Name!</span>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="MicrosoftIdentity" asp-controller="Account" asp-action="SignOut">Sign out</a>
</li>
}
else
{
<li class="nav-item">
<a class="nav-link text-dark" asp-area="MicrosoftIdentity" asp-controller="Account" asp-action="SignIn">Sign in</a>
</li>
}
</ul>
In ASP.NET MVC wird die Schaltfläche Anmelden in Views\Shared\_LoginPartial.cshtml
verfügbar gemacht. Sie wird nur angezeigt, wenn der Benutzer sich noch nicht authentifiziert hat. Das heißt, sie wird angezeigt, wenn sich der Benutzer noch nicht angemeldet oder sich zuvor abgemeldet hat.
@if (Request.IsAuthenticated)
{
// Code omitted code for clarity
}
else
{
<ul class="nav navbar-nav navbar-right">
<li>@Html.ActionLink("Sign in", "SignIn", "Account", routeValues: null, htmlAttributes: new { id = "loginLink" })</li>
</ul>
}
Im Java-Schnellstart befindet sich die Anmeldeschaltfläche in der Datei main/resources/templates/index.html.
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>HomePage</title>
</head>
<body>
<h3>Home Page</h3>
<form action="/msal4jsample/secure/aad">
<input type="submit" value="Login">
</form>
</body>
</html>
Im Node.js-Schnellstart befindet sich der Code für die Anmeldeschaltfläche in der Vorlagendatei index.hbs.
<p>Welcome to {{title}}</p>
<a href="/auth/signin">Sign in</a>
Diese Vorlage wird über die Hauptroute (Index) der App bereitgestellt:
var express = require('express');
var router = express.Router();
router.get('/', function (req, res, next) {
res.render('index', {
title: 'MSAL Node & Express Web App',
isAuthenticated: req.session.isAuthenticated,
username: req.session.account?.username,
});
});
In der Python-Schnellstartanleitung befindet sich der Code für den Anmeldelink in der Vorlagendatei login.html.
<ul><li><a href='{{ auth_uri }}'>Sign In</a></li></ul>
Wenn ein nicht authentifizierter Benutzer die Startseite besucht, leitet die Route index
in app.py den Benutzer zur Route login
um.
@app.route("/")
def index():
if not (app.config["CLIENT_ID"] and app.config["CLIENT_SECRET"]):
# This check is not strictly necessary.
# You can remove this check from your production code.
return render_template('config_error.html')
if not auth.get_user():
return redirect(url_for("login"))
return render_template('index.html', user=auth.get_user(), version=identity.__version__)
Die Route login
ermittelt die geeignete auth_uri
und rendert die Vorlage login.html.
@app.route("/login")
def login():
return render_template("login.html", version=identity.__version__, **auth.log_in(
scopes=app_config.SCOPE, # Have user consent to scopes during log-in
redirect_uri=url_for("auth_response", _external=True), # Optional. If present, this absolute URL must match your app's redirect_uri registered in Azure Portal
))
SignIn
-Aktion des Controllers
+In ASP.NET wird durch Auswahl der Schaltfläche Anmelden in der Web-App die Aktion SignIn
auf dem AccountController
-Controller ausgelöst. In früheren Versionen der ASP.NET Core-Vorlagen war der Account
-Controller in die Web-App eingebettet. Das ist nicht mehr der Fall, da der Controller jetzt Teil des NuGet-Pakets Microsoft.Identity.Web.UI ist. Weitere Informationen finden Sie unter AccountController.cs.
Dieser Controller behandelt auch die Azure AD B2C-Anwendungen.
In ASP.NET wird die Anmeldung von der SignIn()
-Methode auf einem Controller ausgelöst (z. B. AccountController.cs#L16-L23). Diese Methode gehört (im Gegensatz zu den Vorgängen in .NET Core) nicht zum ASP.NET-Framework. Sie sendet eine OpenID-Anmeldeaufforderung, nachdem ein Umleitungs-URI vorgeschlagen wurde.
public void SignIn()
{
// Send an OpenID Connect sign-in request.
if (!Request.IsAuthenticated)
{
HttpContext.GetOwinContext().Authentication.Challenge(new AuthenticationProperties { RedirectUri = "/" }, OpenIdConnectAuthenticationDefaults.AuthenticationType);
}
}
In Java wird die Abmeldung behandelt, indem der logout
-Endpunkt der Microsoft Identity Platform direkt aufgerufen und der Wert post_logout_redirect_uri
bereitgestellt wird. Weitere Informationen finden Sie unter AuthPageController.java#L30-L48.
@Controller
public class AuthPageController {
@Autowired
AuthHelper authHelper;
@RequestMapping("/msal4jsample")
public String homepage(){
return "index";
}
@RequestMapping("/msal4jsample/secure/aad")
public ModelAndView securePage(HttpServletRequest httpRequest) throws ParseException {
ModelAndView mav = new ModelAndView("auth_page");
setAccountInfo(mav, httpRequest);
return mav;
}
// More code omitted for simplicity
Wenn Benutzer*innen den Link Anmelden auswählen, der die Route /auth/signin
auslöst, übernimmt der Anmeldecontroller die Authentifizierung der Benutzer*innen mit Microsoft Identity Platform.
login(options = {}) {
return async (req, res, next) => {
/**
* MSAL Node library allows you to pass your custom state as state parameter in the Request object.
* The state parameter can also be used to encode information of the app's state before redirect.
* You can pass the user's state in the app, such as the page or view they were on, as input to this parameter.
*/
const state = this.cryptoProvider.base64Encode(
JSON.stringify({
successRedirect: options.successRedirect || '/',
})
);
const authCodeUrlRequestParams = {
state: state,
/**
* By default, MSAL Node will add OIDC scopes to the auth code url request. For more information, visit:
* https://docs.microsoft.com/azure/active-directory/develop/v2-permissions-and-consent#openid-connect-scopes
*/
scopes: options.scopes || [],
redirectUri: options.redirectUri,
};
const authCodeRequestParams = {
state: state,
/**
* By default, MSAL Node will add OIDC scopes to the auth code request. For more information, visit:
* https://docs.microsoft.com/azure/active-directory/develop/v2-permissions-and-consent#openid-connect-scopes
*/
scopes: options.scopes || [],
redirectUri: options.redirectUri,
};
/**
* If the current msal configuration does not have cloudDiscoveryMetadata or authorityMetadata, we will
* make a request to the relevant endpoints to retrieve the metadata. This allows MSAL to avoid making
* metadata discovery calls, thereby improving performance of token acquisition process. For more, see:
* https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-node/docs/performance.md
*/
if (!this.msalConfig.auth.cloudDiscoveryMetadata || !this.msalConfig.auth.authorityMetadata) {
const [cloudDiscoveryMetadata, authorityMetadata] = await Promise.all([
this.getCloudDiscoveryMetadata(this.msalConfig.auth.authority),
this.getAuthorityMetadata(this.msalConfig.auth.authority)
]);
this.msalConfig.auth.cloudDiscoveryMetadata = JSON.stringify(cloudDiscoveryMetadata);
this.msalConfig.auth.authorityMetadata = JSON.stringify(authorityMetadata);
}
const msalInstance = this.getMsalInstance(this.msalConfig);
// trigger the first leg of auth code flow
return this.redirectToAuthCodeUrl(
authCodeUrlRequestParams,
authCodeRequestParams,
msalInstance
)(req, res, next);
};
}
redirectToAuthCodeUrl(authCodeUrlRequestParams, authCodeRequestParams, msalInstance) {
return async (req, res, next) => {
// Generate PKCE Codes before starting the authorization flow
const { verifier, challenge } = await this.cryptoProvider.generatePkceCodes();
// Set generated PKCE codes and method as session vars
req.session.pkceCodes = {
challengeMethod: 'S256',
verifier: verifier,
challenge: challenge,
};
/**
* By manipulating the request objects below before each request, we can obtain
* auth artifacts with desired claims. For more information, visit:
* https://azuread.github.io/microsoft-authentication-library-for-js/ref/modules/_azure_msal_node.html#authorizationurlrequest
* https://azuread.github.io/microsoft-authentication-library-for-js/ref/modules/_azure_msal_node.html#authorizationcoderequest
**/
req.session.authCodeUrlRequest = {
...authCodeUrlRequestParams,
responseMode: msal.ResponseMode.FORM_POST, // recommended for confidential clients
codeChallenge: req.session.pkceCodes.challenge,
codeChallengeMethod: req.session.pkceCodes.challengeMethod,
};
req.session.authCodeRequest = {
...authCodeRequestParams,
code: '',
};
try {
const authCodeUrlResponse = await msalInstance.getAuthCodeUrl(req.session.authCodeUrlRequest);
res.redirect(authCodeUrlResponse);
} catch (error) {
next(error);
}
};
}
/**
* Retrieves cloud discovery metadata from the /discovery/instance endpoint
* @returns
*/
async getCloudDiscoveryMetadata(authority) {
const endpoint = 'https://login.microsoftonline.com/common/discovery/instance';
try {
const response = await axios.get(endpoint, {
params: {
'api-version': '1.1',
'authorization_endpoint': `${authority}/oauth2/v2.0/authorize`
}
});
return await response.data;
} catch (error) {
throw error;
}
}
Wenn der Benutzer den Link Anmelden auswählt, wird er zum Microsoft Identity Platform-Autorisierungsendpunkt weitergeleitet.
Bei einer erfolgreichen Anmeldung wird der Benutzer zur Route auth_response
umgeleitet, die den Anmeldevorgang mit auth.complete_login
abschließt, mögliche Fehler rendert und den jetzt authentifizierten Benutzer zur Startseite weiterleitet.
@app.route(app_config.REDIRECT_PATH)
def auth_response():
result = auth.complete_log_in(request.args)
if "error" in result:
return render_template("auth_error.html", result=result)
return redirect(url_for("index"))
Nachdem der Benutzer sich bei Ihrer App angemeldet hat, sollten Sie ihm auch das Abmelden ermöglichen.
Abmeldung
Beim Abmelden von einer Web-App geht es um mehr als um das Entfernen der Informationen zum angemeldeten Konto aus dem Status der Web-App.
Die Web-App muss den Benutzer für die Abmeldung außerdem an den logout
-Endpunkt von Microsoft Identity Platform umleiten.
Wenn Ihre Web-App den Benutzer an den logout
-Endpunkt umleitet, löscht dieser Endpunkt die Sitzung des Benutzers aus dem Browser. Wenn Ihre App nicht den logout
-Endpunkt erreicht hat, kann sich der Benutzer erneut bei Ihrer App authentifizieren, ohne die Anmeldeinformationen erneut eingeben zu müssen. Der Grund hierfür ist, dass er über eine gültige Sitzung für einmaliges Anmelden mit Microsoft Identity Platform verfügt.
Weitere Informationen finden Sie im Abschnitt Senden einer Abmeldeanforderung in der Dokumentation zu Microsoft Identity Platform und OpenID Connect-Protokoll.
Anwendungsregistrierung
Bei der Anwendungsregistrierung registrieren Sie eine Front-Channel-Abmelde-URL. In unserem Tutorial haben Sie https://localhost:44321/signout-oidc
im Feld Front-Channel-Abmelde-URL auf der Seite Authentifizierung registriert. Weitere Informationen finden Sie unter Registrieren der webApp-App.
Bei der Anwendungsregistrierung müssen Sie keine zusätzliche Front-Channel-Abmelde-URL registrieren. Die App wird über die Haupt-URL zurückgerufen.
Bei der Anwendungsregistrierung ist keine Front-Channel-Abmelde-URL erforderlich.
Bei der Anwendungsregistrierung ist keine Front-Channel-Abmelde-URL erforderlich.
Bei der Anwendungsregistrierung müssen Sie keine zusätzliche Front-Channel-Abmelde-URL registrieren. Die App wird über die Haupt-URL zurückgerufen.
In ASP.NET wird durch Auswahl der Schaltfläche Abmelden in der Web-App die Aktion SignOut
auf dem AccountController
-Controller ausgelöst (siehe unten).
<ul class="navbar-nav">
@if (User.Identity.IsAuthenticated)
{
<li class="nav-item">
<span class="navbar-text text-dark">Hello @User.Identity.Name!</span>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="MicrosoftIdentity" asp-controller="Account" asp-action="SignOut">Sign out</a>
</li>
}
else
{
<li class="nav-item">
<a class="nav-link text-dark" asp-area="MicrosoftIdentity" asp-controller="Account" asp-action="SignIn">Sign in</a>
</li>
}
</ul>
In ASP.NET MVC wird die Abmeldeschaltfläche in Views\Shared\_LoginPartial.cshtml
verfügbar gemacht. Sie wird nur angezeigt, wenn ein authentifiziertes Konto vorhanden ist. Das heißt, sie wird angezeigt, wenn sich der Benutzer zuvor angemeldet hat.
@if (Request.IsAuthenticated)
{
<text>
<ul class="nav navbar-nav navbar-right">
<li class="navbar-text">
Hello, @User.Identity.Name!
</li>
<li>
@Html.ActionLink("Sign out", "SignOut", "Account")
</li>
</ul>
</text>
}
else
{
<ul class="nav navbar-nav navbar-right">
<li>@Html.ActionLink("Sign in", "SignIn", "Account", routeValues: null, htmlAttributes: new { id = "loginLink" })</li>
</ul>
}
In unserem Java-Schnellstart befindet sich die Abmeldeschaltfläche in der Datei „main/resources/templates/auth_page.html“.
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<body>
<form action="/msal4jsample/sign_out">
<input type="submit" value="Sign out">
</form>
...
{{#if isAuthenticated }}
<a href="/auth/signout">Sign out</a>
In der Python-Schnellstartanleitung befindet sich die Abmeldeschaltfläche in der Datei templates/index.html.
<li><a href="/logout">Logout</a></li>
SignOut
-Aktion des Controllers
In früheren Versionen der ASP.NET Core-Vorlagen war der Account
-Controller in die Web-App eingebettet. Das ist nicht mehr der Fall, da der Controller jetzt Teil des NuGet-Pakets Microsoft.Identity.Web.UI ist. Weitere Informationen finden Sie unter AccountController.cs.
Sie legt einen OpenID-Umleitungs-URI auf /Account/SignedOut
fest, damit der Controller zurückgerufen wird, wenn Microsoft Entra ID die Abmeldung abgeschlossen hat.
Sie ruft Signout()
auf, damit die OpenID Connect-Middleware den logout
-Endpunkt der Microsoft Identity Platform kontaktieren kann. Der Endpunkt führt dann folgende Aktionen aus:
- Er löscht den Sitzungscookie im Browser.
- Er ruft den Umleitungs-URI nach der Abmeldung zurück. Standardmäßig zeigt der Umleitungs-URI nach der Abmeldung SignedOut.cshtml.cs an. Diese Seite wird auch als Teil von Microsoft.Identity.Web bereitgestellt.
In ASP.NET wird die Abmeldung von der SignOut()
-Methode auf einem Controller ausgelöst (z. B. AccountController.cs#L25-L31). Diese Methode gehört im Gegensatz zu den Vorgängen in .NET Core nicht zum ASP.NET-Framework. Sie hat folgende Aufgaben:
- Sie sendet eine OpenID-Abmeldeaufforderung.
- Sie löscht den Cache.
- Sie leitet auf die gewünschte Seite um.
/// <summary>
/// Send an OpenID Connect sign-out request.
/// </summary>
public void SignOut()
{
HttpContext.GetOwinContext()
.Authentication
.SignOut(CookieAuthenticationDefaults.AuthenticationType);
Response.Redirect("/");
}
In Java wird die Abmeldung behandelt, indem der logout
-Endpunkt der Microsoft Identity Platform direkt aufgerufen und der Wert post_logout_redirect_uri
bereitgestellt wird. Weitere Informationen finden Sie unter AuthPageController.java#L50-L60.
@RequestMapping("/msal4jsample/sign_out")
public void signOut(HttpServletRequest httpRequest, HttpServletResponse response) throws IOException {
httpRequest.getSession().invalidate();
String endSessionEndpoint = "https://login.microsoftonline.com/common/oauth2/v2.0/logout";
String redirectUrl = "http://localhost:8080/msal4jsample/";
response.sendRedirect(endSessionEndpoint + "?post_logout_redirect_uri=" +
URLEncoder.encode(redirectUrl, "UTF-8"));
}
Wenn Benutzer*innen die Schaltfläche Abmelden auswählen, löst die App die Route /auth/signout
aus, die die Sitzung zerstört und den Browser an den Abmeldeendpunkt von Microsoft Identity Platform umleitet.
logout(options = {}) {
return (req, res, next) => {
/**
* Construct a logout URI and redirect the user to end the
* session with Azure AD. For more information, visit:
* https://docs.microsoft.com/azure/active-directory/develop/v2-protocols-oidc#send-a-sign-out-request
*/
let logoutUri = `${this.msalConfig.auth.authority}/oauth2/v2.0/`;
if (options.postLogoutRedirectUri) {
logoutUri += `logout?post_logout_redirect_uri=${options.postLogoutRedirectUri}`;
}
req.session.destroy(() => {
res.redirect(logoutUri);
});
}
}
Wenn der Benutzer die Schaltfläche Abmelden auswählt, löst die App die Route logout
aus, die den Browser an den Abmeldeendpunkt der Microsoft Identity Platform umleitet.
@app.route("/logout")
def logout():
return redirect(auth.log_out(url_for("index", _external=True)))
Abfangen des Aufrufs an den logout
-Endpunkt
Der URI nach der Abmeldung ermöglicht Anwendungen, an der globalen Abmeldung teilzunehmen.
Mit der OpenID Connect-Middleware von ASP.NET Core kann Ihre App den Aufruf an den logout
-Endpunkt der Microsoft Identity Platform durch die Bereitstellung des OpenID Connect-Ereignisses OnRedirectToIdentityProviderForSignOut
abfangen. Dies erfolgt automatisch durch Microsoft.Identity.Web (indem Konten gelöscht werden, wenn Ihre Web-App Web-APIs aufruft).
In ASP.NET delegieren Sie die Ausführung der Abmeldung an die Middleware, indem Sie das Sitzungscookie löschen:
public class AccountController : Controller
{
...
public void EndSession()
{
Request.GetOwinContext().Authentication.SignOut();
Request.GetOwinContext().Authentication.SignOut(Microsoft.AspNet.Identity.DefaultAuthenticationTypes.ApplicationCookie);
this.HttpContext.GetOwinContext().Authentication.SignOut(CookieAuthenticationDefaults.AuthenticationType);
}
}
Im Java-Schnellstart zeigt der Umleitungs-URI nach der Abmeldung nur die Seite „index.html“ an.
Im Node-Schnellstart wird der Umleitungs-URI nach der Abmeldung verwendet, um den Browser zurück zur Beispielstartseite umzuleiten, nachdem die Benutzer*innen den Abmeldevorgang mit Microsoft Identity Platform abgeschlossen haben.
In der Python-Schnellstartanleitung zeigt die URI für die Umleitung nach dem Logout nur die Seite index.html an.
Protocol
Weitere Informationen zum Abmelden finden Sie in der Protokolldokumentation, die über OpenID Connect verfügbar ist.
Nächste Schritte
Erfahren Sie mehr, indem Sie in der folgenden mehrteiligen Tutorialreihe eine ASP.NET Core-Webanwendung für die Anmeldung von Benutzern erstellen
Erkunden von Beispielen für Webanwendungen der Microsoft-Identitätsplattform