Azure AD B2C / Azure AD, usando Client Credencial
Aplicações que Autenticam em outras aplicações
O Azure AD B2C não fornece diretamente o fluxo Client Credencial, mas como todo B2C tem um AD por traz dele trabalhando em conjunto, podemos usar esse recurso para suprir esse fluxo OAuth2.
O Fluxo Client Credencial não autentica um usuário como o Autorization Code Flow , ou o Fluxo Implícito, esse fluxo autentica uma aplicação, desse modo podemos proteger nossas APIs autorizando apenas o APIM a fazer requisições nela.
A primeira coisa que precisamos fazer é criar as aplicações no AD, para isso vamos analisar o modelo;
Então precisamos de pelo menos três aplicações para representar esses clientes sendo que dois deles precisam ter Client /Secret Configurados no Azure AD.
Vamos precisar criar as aplicações, mas nesse caso vamos cria-las diretamente no Azure AD do tenant do Azure B2C.
Saiba mais sobre criar aplicações aqui
Não se esqueça de configurar as devidas permissões,normalmente precisamos ter uma App que representa o Servidor e uma que representa o Cliente, ai expomos uma URI na aplicação do Server e damos permissão na aplicação cliente nessa URI.
Essa permissão quando o fluxo é de usuário usamos Escopos, e quando o fluxo é de aplicação usamos Roles.
No caso do nosso cenário precisamos criar uma Role por se tratar de fluxo entre aplicações ;
Depois de criar as aplicações o primeiro passo e proteger a API com o código Abaixo;
Vou criar uma controller protegida com o atributo Authorize, chamada SecurityDataController
[ApiController]
[Route("[controller]")]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public class SecretDataController : ControllerBase
{
public IActionResult Index()
{
return Ok(new
{
msg = "My Secret"
});
}
}
Vou usar um console para fazer um teste Inicial, nele precisamos obter um token e passar na requisição ;
olha ai tudo funciona;
Agora a cereja do bolo, como podemos fazer o APIM obter um token CC e chamar esse backend, permitindo que o cliente do APIM use outro fluxo de Autenticação por exemplo.
APIM repassando o token para o Backend
Importei a API no APIM , e configurei a police validate-jwt
Mas diferente do ultimo exemplo que nosso .well-known vinha do B2C com esse endpoint
https://seedazb2c.b2clogin.com/seedazb2c.onmicrosoft.com/v2.0/.well-known/openid-configuration?p=B2C_1_seed_sso
Dessa vez vamos usar outra url
https://login.microsoftonline.com/b5882312-aafa-467b-b071-96db714bd4f5/v2.0/.well-known/openid-configuration
Encontrei essa url abrindo o token pelo jwt.io
Peguei o valor da claim iss e completei com .well-known/openid-configuration
<validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Acesso negado">
<openid-config
url="https://login.microsoftonline.com/b5882312-aafa-467b-b071-96db714bd4f5/v2.0/.well-known/openid-configuration" />
</validate-jwt>
funcionou perfeitamente
Obtive o token debugando a aplicação console, passei esse token no header Authorization e consegui acessar minha controller protegida SecretData
APIM obtendo o token e repassando para o backend
Nesse exemplo vamos fazer a chamada para o AD , obter o token e repassar o mesmo para o backend
- Bate na url do AD “/token” com método post, content type application/x-www-form-urlencoded e o body com os campos client_id, client_secret, grant_type e scope
- Extrai a da variável tokenResponse o acces_token
- Sobrescreve o header da requisição ao backend com o access token
Obtendo dados do usuário da Assinatura
Podemos obter algumas informações do usuário da assinatura utilizada na requisição as APIs, quando os consumidores acessam as APIs do APIM é comum que o header Ocp-Apim-Subscription-Key seja fornecido. Quando essa chave é associada à um usuário de assinatura, podemos obter informações como o e-mail quem fez a assinatura no portal do desenvolvedor.
Por exemplo adicionando esse código no outbound
<set-header name="useId" exists-action="override">
<value>@(JsonConvert.SerializeObject(context.User != null ? context.User.Email: "-"))</value>
</set-header>
Vamos ter esse retorno no postman;
Podemos colocar o mesmo código no inbound e vamos enviar esse valor para o backend.
Named Values
Todos os valores Hardcode nas politicas acima podem ser transferidos para o Named Value, um espaço de chave valor no APIM que pode ser usado para centralizar esse tipo de coisa facilitando a manutenção assim como a mudança de ambientes.
e depois para acessar basta fazer uma interpolação, assim;
<set-body>@{
var result = String.Concat
(
"client_id={{ClientIDAPIM}}&",
"client_secret={{SecretAPIM}}&",
"grant_type=client_credentials&",
"scope=https://seedazb2c.onmicrosoft.com/services/.default"
);
return result;
}</set-body>
bem mais bonito!
Cache
Uma boa pratica para escalar um back-end é o uso de cache, com o APIM podemos habilitar cache de duas formas, uma mais simples apenas copiando e colando duas politicas cache-lookup e cache-store veja aqui, e outra onde podemos controlar o cache com uma chave parecido com o que faríamos com o Redis.
No caso do send-request vamos precisar gerenciar o cache através de uma chave via código usando a diretiva cache-lookup-value, observe o código abaixo;
- Verificamos no cache a chave tokenCCV1 e jogamos para variável accessToken usando a politica cache-lookup-value
- Verificamos se a variável accessToken foi criada usando a politica when
- Caso não tenha sido criado fazemos o send-request e armazenamos o aceestoken no cache usando a politica cache-store-value
- Caso tenha sido criado pulamos o send-request e passamos para o backend a variável de contexto accessToken
Controle de Expiração baseado no token
Para a implementação final de produção talvez seja uma boa ideia ler o token acessar a claim exp e verificar se a mesma expirou ou não, esse critério deve fazer parte da verificação inicial da política When, de modo que caso exista um token no cache mas o mesmo esteja expirado devemos fazer o request novamente
Referencias
- Sample Azure API management policy — Use OAuth2 for authorization between gateway and backend — Azure API Management | Microsoft Docs
- Client Credentials Grant Flow with Azure AD B2C · Hossam Barakat
- Azure API Management policy expressions | Microsoft Docs
- Repositorio GIT backend
- Custom caching in Azure API Management | Microsoft Docs