No ASP.NET Core, para aplicativos da plataforma de identidade da Microsoft, o botão Entrar é exposto em Views\Shared\_LoginPartial.cshtml (em um aplicativo MVC) ou Pages\Shared\_LoginPartial.cshtm (em um aplicativo Razor). Ele só é exibido quando o usuário não foi autenticado. Ou seja, ele é exibido quando o usuário ainda não se conectou ou quando ele se desconectou. Por outro lado, o botão Sair é exibido quando o usuário já está conectado. Observe que o controlador de conta está definido no pacote NuGet Microsoft.Identity.Web.UI, na área chamada MicrosoftIdentity
No MVC do ASP.NET, o botão Entrar é exposto em Views\Shared\_LoginPartial.cshtml. Ele só é exibido quando o usuário não foi autenticado. Ou seja, ele é exibido quando o usuário ainda não entrou ou saiu.
Quando um usuário não autenticado visita a página inicial, a rota index em app.py redireciona o usuário para a rota login.
@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 rota login descobre o auth_uri apropriado e renderiza o modelo 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
))
No ASP.NET, a seleção do botão Entrar no aplicativo Web dispara a ação SignIn no controlador AccountController. Nas versões anteriores dos modelos do ASP.NET Core, o controlador Account era incorporado ao aplicativo Web. Isso não ocorre mais, porque o controlador agora faz parte do pacote NuGet Microsoft.Identity.Web.UI. Confira AccountController.cs para obter detalhes.
Esse controlador também lida com os aplicativos Azure AD B2C.
No ASP.NET, a entrada é disparada pelo método SignIn() em um controlador (por exemplo, AccountController.cs#L16-L23). Esse método não faz parte do .NET Framework (ao contrário do que acontece no ASP.NET Core). Ele envia um desafio de entrada do OpenID depois de 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);
}
}
No Java, a saída é tratada por uma chamada direta ao ponto de extremidade logout da plataforma de identidade da Microsoft e pela inserção do valor post_logout_redirect_uri. Para obter detalhes, confira 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 usuário seleciona o link Entrar, que dispara a rota /auth/signin, o controlador de entrada assume o controle para autenticar o usuário na 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 usuário seleciona o link Entrar, ele é levado para o ponto de extremidade de autorização da Plataforma de Identidade da Microsoft.
Uma entrada bem-sucedida redireciona o usuário para a rota auth_response, que conclui o processo de entrada usando auth.complete_login, renderiza os erros, se houver, e redireciona o usuário agora 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 que o usuário entrar no seu aplicativo, o ideal será permitir que ele saia dele.
Sair
A saída de um aplicativo Web envolve mais aspectos do que a remoção das informações sobre a conta conectada do estado do aplicativo Web.
O aplicativo Web também precisa redirecionar o usuário para o ponto de extremidade logout da plataforma de identidade da Microsoft para que ele saia dele.
Quando seu aplicativo Web redireciona o usuário para o ponto de extremidade logout, esse ponto de extremidade limpa a sessão do usuário do navegador. Se o seu aplicativo não for para o ponto de extremidade logout, o usuário será autenticado novamente no aplicativo sem inserir as credenciais novamente. O motivo disso é que ele terá uma sessão de logon único válida na plataforma de identidade da Microsoft.
Durante o registro de aplicativo, registre uma URL de logoff de front-channel. No tutorial, você registrou https://localhost:44321/signout-oidc no campo URL de logoff de front-channel na página Autenticação. Para obter detalhes, confira Registrar o aplicativo webApp.
Durante o registro de aplicativo, não é necessário registrar uma URL extra de logoff de front-channel. O aplicativo será chamado novamente na URL principal.
Nenhuma URL de logoff de front-channel é necessária no registro de aplicativo.
Nenhuma URL de logoff de front-channel é necessária no registro de aplicativo.
Durante o registro de aplicativo, não é necessário registrar uma URL extra de logoff de front-channel. O aplicativo será chamado novamente na URL principal.
No ASP.NET MVC, o botão de saída é exposto em Views\Shared\_LoginPartial.cshtml. Ele só é exibido quando há uma conta autenticada. Ou seja, ele é exibido quando o usuário se conectou anteriormente.
Nas versões anteriores dos modelos do ASP.NET Core, o controlador Account era incorporado ao aplicativo Web. Isso não ocorre mais, porque o controlador agora faz parte do pacote NuGet Microsoft.Identity.Web.UI. Confira AccountController.cs para obter detalhes.
Define um URI de redirecionamento do OpenID como /Account/SignedOut para que o controlador seja chamado novamente quando o Microsoft Entra ID concluir a saída.
Chama Signout(), que permite ao middleware do OpenID Connect entrar em contato com o ponto de extremidade logout da plataforma de identidade da Microsoft. Em seguida, o ponto de extremidade:
Limpará o cookie de sessão do navegador.
Chamará novamente o URI de redirecionamento pós-logoff. Por padrão, o URI de redirecionamento pós-logoff mostra a página de exibição de desconexão SignedOut.cshtml.cs. Essa página também é fornecida como parte do Microsoft.Identity.Web.
No ASP.NET, a saída é disparada pelo método SignOut() em 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. It:
Envia um desafio de desconexão do OpenID.
Limpa o cache.
Redireciona o usuário 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("/");
}
No Java, a saída é tratada por uma chamada direta ao ponto de extremidade logout da plataforma de identidade da Microsoft e pela inserção do valor post_logout_redirect_uri. Para obter detalhes, confira AuthPageController.java#L50-L60.
Quando o usuário seleciona o botão Sair, o aplicativo dispara a rota /auth/signout, que destrói a sessão e redireciona o navegador para o ponto de extremidade de saída 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 usuário seleciona Sair, o aplicativo aciona a rota logout, que redireciona o navegador para o ponto de extremidade de saída da plataforma de identidade da Microsoft.
O middleware do OpenID Connect para ASP.NET Core permite que o seu aplicativo intercepte a chamada ao ponto de extremidade logout da plataforma de identidade da Microsoft fornecendo um evento do OpenID Connect chamado OnRedirectToIdentityProviderForSignOut. Isso é tratado automaticamente pelo Microsoft.Identity.Web (que limpa as contas caso o aplicativo Web chame APIs Web)
No ASP.NET, você delega ao middleware para que ele execute a saída, 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 guia de início rápido do Java, o URI de redirecionamento pós-logoff apenas exibe a página index.html.
No início rápido do Nó, o URI de redirecionamento pós-logoff é usado para redirecionar o navegador de volta para a home page de exemplo depois que o usuário concluir o processo de logoff com a plataforma de identidade da Microsoft.
No início rápido do Python, o URI de redirecionamento após o logout apenas exibe a página index.html.
Protocolo
Caso deseje saber mais sobre a saída, leia a documentação do protocolo disponível em Open ID Connect.
Próximas etapas
Saiba mais sobre a compilar de um aplicativo Web ASP.NET Core que conecta usuários na seguinte série de tutoriais de várias partes