Aplica-se a:
Locatários de trabalho
Locatários externos (saiba mais)
Saiba como adicionar o início de sessão ao código da sua aplicação web que permite o início de sessão dos utilizadores. Em seguida, saiba como deixá-los sair.
Iniciar sessão
O início de sessão consiste em duas partes:
- O botão de início de sessão na página HTML
- A ação de iniciar sessão no code-behind no controlador
No ASP.NET Core, para aplicativos da plataforma de identidade da Microsoft, o botão Entrar é exposto em Views\Shared\_LoginPartial.cshtml
(para um aplicativo MVC) ou Pages\Shared\_LoginPartial.cshtm
(para um aplicativo Razor). Ele é exibido somente quando o usuário não está autenticado. Ou seja, o botão é exibido quando o utilizador ainda não iniciou sessão ou terminou sessão. Por outro lado, o botão Terminar Sessão é exibido quando o utilizador já iniciou sessão. O controlador de conta é definido no pacote NuGet Microsoft.Identity.Web.UI , na área chamada MicrosoftIdentity
<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>
No ASP.NET MVC, o botão Entrar é exposto em Views\Shared\_LoginPartial.cshtml
. Ele é exibido somente quando o usuário não está autenticado. Ou seja, ele é exibido quando o usuário ainda não entrou ou saiu.
@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>
}
No início rápido do Java, o botão de login está localizado no arquivo 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>
No início rápido do Node.js, o código do botão de entrada está localizado no arquivo de modelo index.hbs .
<p>Welcome to {{title}}</p>
<a href="/auth/signin">Sign in</a>
Este modelo é servido através da rota principal (índice) do aplicativo:
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,
});
});
No guia rápido do Python, o código para o link de iniciar sessão está localizado no ficheiro de modelo login.html.
<ul><li><a href='{{ auth_uri }}'>Sign In</a></li></ul>
Quando um usuário não autenticado visita a página inicial, a index
rota no app.py redireciona o usuário para a login
rota.
@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__)
A login
rota determina o apropriado auth_uri
e renderiza o template 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
Ação do responsável pelo tratamento
No ASP.NET, selecionar o botão Entrar no aplicativo Web dispara a SignIn
ação no AccountController
controlador. Em versões anteriores dos modelos ASP.NET Core, o Account
controlador era incorporado ao aplicativo Web. Isso não é mais o caso porque o controlador agora faz parte do pacote NuGet Microsoft.Identity.Web.UI . Consulte AccountController.cs para obter detalhes.
Este controlador também lida com os aplicativos do Azure AD B2C.
No ASP.NET, o login é acionado a partir do SignIn()
método em um controlador (por exemplo, AccountController.cs#L16-L23). Este método não faz parte do .NET Framework (ao contrário do que acontece no ASP.NET Core). Ele envia um desafio de login OpenID após propor um URI de redirecionamento.
public void SignIn()
{
// Send an OpenID Connect sign-in request.
if (!Request.IsAuthenticated)
{
HttpContext.GetOwinContext().Authentication.Challenge(new AuthenticationProperties { RedirectUri = "/" }, OpenIdConnectAuthenticationDefaults.AuthenticationType);
}
}
Em Java, sair é tratado chamando o ponto de extremidade da plataforma de identidade da Microsoft logout
diretamente e fornecendo o valor post_logout_redirect_uri
. Para obter detalhes, consulte 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
Quando o utilizador seleciona o link Entrar, que aciona a rota /auth/signin
, o controlador de início de sessão assume o comando para autenticar o utilizador com a plataforma de identidade da Microsoft.
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;
}
}
Quando o utilizador seleciona a ligação de Início de Sessão, ele é direcionado para o endpoint de autorização da plataforma de identidade da Microsoft.
Um início de sessão bem-sucedido redireciona o usuário para a rota auth_response
, que conclui o processo de início de sessão usando auth.complete_login
, apresenta erros, se houver, e redireciona o usuário autenticado para a página inicial.
@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"))
Depois de o utilizador iniciar sessão na sua aplicação, desejará permitir-lhe terminar sessão.
Terminar sessão
Sair de um aplicativo Web envolve mais do que remover as informações sobre a conta conectada do estado do aplicativo Web.
A aplicação web também deve redirecionar o utilizador para o ponto final da plataforma de identidade da Microsoft logout
para terminar a sessão.
Quando o seu aplicativo Web redireciona o utilizador para o ponto de extremidade logout
, esse ponto de extremidade limpa a sessão do utilizador no navegador. Se a sua aplicação não alcançou o ponto de extremidade logout
, o utilizador pode reauntenticar-se na sua aplicação sem inserir novamente as credenciais. O motivo é que eles terão uma sessão de logon único válida com a plataforma de identidade da Microsoft.
Para saber mais, consulte a seção Enviar uma solicitação de saída na plataforma de identidade da Microsoft e na documentação do protocolo OpenID Connect .
Registo de Aplicativo
Durante o registro do aplicativo, você registra uma URL de logout do canal frontal. No nosso tutorial, registou https://localhost:44321/signout-oidc
no campo URL de logout do canal frontal na página de Autenticação. Para obter detalhes, consulte Registrar o aplicativo webApp.
Durante o registo da aplicação, não é necessário registar uma URL de terminação de sessão extra do canal principal. A aplicação é redirecionada para o seu URL principal.
Nenhum URL de logout do canal frontal é necessário no registro do aplicativo.
Nenhum URL de logout do canal frontal é necessário no registro do aplicativo.
Durante o registo da aplicação, não é necessário registar uma URL de terminação de sessão extra do canal principal. A aplicação é redirecionada para o seu URL principal.
No ASP.NET, selecionar o botão Sair na aplicação web dispara a SignOut
ação no AccountController
controlador (veja abaixo)
<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>
No ASP.NET MVC, o botão de saída é exposto em Views\Shared\_LoginPartial.cshtml
. Ele é exibido somente quando há uma conta autenticada. Ou seja, ele é exibido quando o usuário fez login anteriormente.
@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>
}
No nosso guia de início rápido do Java, o botão de saída está localizado no arquivo 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>
No início rápido do Python, o botão de saída está localizado no arquivo templates/index.html .
<li><a href="/logout">Logout</a></li>
SignOut
Ação do responsável pelo tratamento
Em versões anteriores dos modelos ASP.NET Core, o Account
controlador era incorporado ao aplicativo Web. Isso não é mais o caso porque o controlador agora faz parte do pacote NuGet Microsoft.Identity.Web.UI . Consulte AccountController.cs para obter detalhes.
Configura um URI de redirecionamento OpenID para /Account/SignedOut
de modo que o controlador seja chamado de volta quando o Microsoft Entra ID tiver concluído o encerramento da sessão.
Chama Signout()
, o que permite que o middleware OpenID Connect entre em contato com o ponto de extremidade da plataforma de identidade da Microsoft logout
. O ponto final, então:
- Limpa o cookie de sessão do navegador.
- Chama de volta o URI de redirecionamento pós-logout. Por padrão, o URI de redirecionamento pós-logout exibe a página de visualização de sessão terminada SignedOut.cshtml.cs. Esta página também é fornecida como parte do Microsoft.Identity.Web.
No ASP.NET, a saída é acionada a partir do método SignOut()
de um controlador (por exemplo, AccountController.cs#L25-L31). Esse método não faz parte do .NET Framework, ao contrário do que acontece no ASP.NET Core. Isso:
- Envia um pedido de encerramento de sessão do OpenID.
- Limpa o cache.
- Redireciona para a página desejada.
/// <summary>
/// Send an OpenID Connect sign-out request.
/// </summary>
public void SignOut()
{
HttpContext.GetOwinContext()
.Authentication
.SignOut(CookieAuthenticationDefaults.AuthenticationType);
Response.Redirect("/");
}
Em Java, sair é tratado chamando o ponto de extremidade da plataforma de identidade da Microsoft logout
diretamente e fornecendo o valor post_logout_redirect_uri
. Para obter detalhes, consulte 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"));
}
Quando o utilizador seleciona o botão Sair, o aplicativo ativa a rota /auth/signout
, que destrói a sessão e redireciona o navegador para o endpoint de terminação da plataforma de identidade da Microsoft.
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);
});
}
}
Quando o utilizador seleciona Logout, o aplicativo ativa a rota logout
, que redireciona o navegador para o ponto de terminação de sessão da plataforma de identidade da Microsoft.
@app.route("/logout")
def logout():
return redirect(auth.log_out(url_for("index", _external=True)))
Interceptando a chamada para o logout
endpoint
O URI pós-logout permite que os aplicativos participem do logout global.
O middleware ASP.NET Core OpenID Connect permite que a sua aplicação intercepte a chamada para o endpoint da plataforma de identidade da Microsoft, fornecendo um evento OpenID Connect chamado logout
. Isso é tratado automaticamente pelo Microsoft.Identity.Web (que limpa contas no caso em que seu aplicativo Web chama APIs da Web).
No ASP.NET, você delega ao middleware para executar o logout, limpando o cookie de sessão:
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);
}
}
No início rápido do Java, o URI de redirecionamento pós-logout exibe apenas a página index.html.
No Início Rápido do Node, o URI de redirecionamento pós-logout é usado para redirecionar o navegador de volta para a página inicial do exemplo depois que o utilizador conclui o processo de saída com a plataforma de identidade da Microsoft.
No início rápido do Python, o URI de redirecionamento pós-logout exibe apenas a página index.html .
Protocolo
Se quiser saber mais sobre como sair, leia a documentação do protocolo disponível no OpenID Connect.
Próximos passos
Saiba mais criando uma aplicação Web ASP.NET Core que inicia sessão para utilizadores na seguinte série de tutoriais em várias partes
Explore exemplos de aplicativos Web da plataforma de identidade da Microsoft