Autenticação e Autorização numa Aplicação Web API através de uma aplicação Cliente ASP.NET MVC Secure a Web API with Individual Accounts and Local Login in ASP.NET Web API 2.2 http:www.asp.net/web-api/overview/security/individual-accounts-in-web-api 1. Criar a aplicação ASP.NET Web API Visual Studio 2015 > File > New Project > Web > ASP.NET Web Application Name: WebApiAuth OK ASP.NET 4.6 Templates: Web API Authentication: Individual User Accounts OK 1.1. Executar a aplicação Copiar o url base da aplicação http:localhost:xxxxx/ 2. Criar a Aplicação ASP.NET MVC (Cliente da Aplicação Web API 2) Criar outra Solução Visual Studio com uma Aplicação Web MVC 5, cliente da Web API 2 (usando HttpClient) Visual Studio 2015 > File > New Project > Web > ASP.NET Web Application Name: ClienteMvcAuth OK ASP.NET 4.6 Templates: MVC Authentication: Individual User Accounts OK 2.1. Criar uma pasta Helpers para conter a classe de acesso à Web API ClienteMvcAuth> botão direito do rato: Add > New Folder > Helpers Helpers > botão direito do rato: Add > Class > Name: WebApiHttpClient.cs Add using System; using System.Net.Http; namespace ClienteMvcAuth.Helpers public static class WebApiHttpClient public const string WebApiBaseAddress = "http:localhost:1742/"; public static HttpClient GetClient() HttpClient client = new HttpClient(); client.baseaddress = new Uri(WebApiBaseAddress); client.defaultrequestheaders.accept.clear(); client.defaultrequestheaders.accept.add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json")); return client;
Necessário mudar a localização do serviço Web API na constante WebApiBaseAddress. Configurámos no objeto HttpClient: a propriedade BaseAddress com o endereço do serviço Web API a propriedade DefaultRequestHeaders para que o formato da resposta do serviço seja apenas o formato JSON. Começámos por fazer Clear() e depois adicionámos o formato "application/json" 3. Método Post Register de AccountController Inicial: POST: /Account/Register public async Task<ActionResult> Register(RegisterViewModel model) if (ModelState.IsValid) var user = new ApplicationUser UserName = model.email, Email = model.email ; var result = await UserManager.CreateAsync(user, model.password); if (result.succeeded) await SignInManager.SignInAsync(user, ispersistent:false, rememberbrowser:false); return RedirectToAction("Index", "Home"); AddErrors(result); If we got this far, something failed, redisplay form Alterar para: POST: /Account/Register public async Task<ActionResult> Register(RegisterViewModel model) if (ModelState.IsValid)
var data = new Email = model.email, Password = model.password, ConfirmPassword = model.password ; try var client = WebApiHttpClient.GetClient(); string datajson = JsonConvert.SerializeObject(data); HttpContent content = new StringContent(dataJSON, System.Text.Encoding.Unicode, "application/json"); var response = await client.postasync("api/account/register", content); if (response.issuccessstatuscode) return RedirectToAction("Index", "Home"); else return Content("Ocorreu um erro: " + response.statuscode); catch return Content("Ocorreu um erro."); If we got this far, something failed, redisplay form 3.1. Testar o Registo de um utilizador Executar a aplicação Web API (WebApiAuth). Copiar o endereço base do serviço e colocar na classe helper WebApiHttpClient da aplicação Cliente MVC (ClienteMvcAuth). Executar a aplicação Cliente MVC (ClienteMvcAuth). Clicar no botão Register e registar um utilizador. Verificar se o utilizador ficou registado na tabela AspNetUsers da base de dados da aplicação Web API. 4. Método Post Login de AccountController Inicial: POST: /Account/Login public async Task<ActionResult> Login(LoginViewModel model, string returnurl) if (!ModelState.IsValid)
This doesn't count login failures towards account lockout To enable password failures to trigger account lockout, change to shouldlockout: true var result = await SignInManager.PasswordSignInAsync(model.Email, model.password, model.rememberme, shouldlockout: false); switch (result) case SignInStatus.Success: return RedirectToLocal(returnUrl); case SignInStatus.LockedOut: return View("Lockout"); case SignInStatus.RequiresVerification: return RedirectToAction("SendCode", new ReturnUrl = returnurl, RememberMe = model.rememberme ); case SignInStatus.Failure: default: ModelState.AddModelError("", "Invalid login attempt."); Alterar para: POST: /Account/Login public async Task<ActionResult> Login(LoginViewModel model, string returnurl) if (!ModelState.IsValid) try var client = WebApiHttpClient.GetClient(); string username = model.email; string password = model.password; HttpContent content = new StringContent( "grant_type=password&username=" + username + "&password=" + password, System.Text.Encoding.UTF8, "application/x-www-form-urlencoded"); var response = await client.postasync("/token", content); if (response.issuccessstatuscode) TokenResponse tokenresponse = await response.content.readasasync<tokenresponse>(); WebApiHttpClient.storeToken(tokenResponse); return Content(tokenResponse.AccessToken); return RedirectToAction("Index", "Home"); else return Content("Ocorreu um erro: " + response.statuscode); catch return Content("Ocorreu um erro.");
Na pasta Helpers criar uma classe TokenResponse que representa o modelo da resposta enviada pelo Servidor de Autenticação existente na Web Api: public class TokenResponse [JsonProperty("access_token")] public string AccessToken get; set; [JsonProperty("token_type")] public string TokenType get; set; [JsonProperty("expires_in")] public int ExpiresIn get; set; [JsonProperty("userName")] public string Username get; set; [JsonProperty(".issued")] public string IssuedAt get; set; [JsonProperty(".expires")] public string ExpiresAt get; set; Na pasta Helpers alterar a classe WebApiHttpClient, para o objeto HttpClient enviar um cabeçalho de Autorização depois de receber o Access Token. namespace ClienteMvcAuth.Helpers public static class WebApiHttpClient public const string WebApiBaseAddress = "http:localhost:1742/"; public static HttpClient GetClient() HttpClient client = new HttpClient(); client.baseaddress = new Uri(WebApiBaseAddress); client.defaultrequestheaders.accept.clear(); client.defaultrequestheaders.accept.add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json")); var session = HttpContext.Current.Session; if (session["token"]!= null) TokenResponse tokenresponse = gettoken(); client.defaultrequestheaders.authorization = new AuthenticationHeaderValue("bearer", tokenresponse.accesstoken); return client; public static void storetoken(tokenresponse token) var session = HttpContext.Current.Session; session["token"] = token; public static TokenResponse gettoken() var session = HttpContext.Current.Session; return (TokenResponse) session["token"];
4.1. Testar o Login de um utilizador Executar o Serviço (aplicação Web API, WebApiAuth) e o Cliente (aplicação MVC, ClienteMvcAuth). Clicar no botão Login para autenticar um utilizador 4.2. Ver o Access Token criado pelo Servidor de Autenticação no Login de um utilizador Executar o código anterior comentando, no método POST Login de AccountController, a instrução que guarda num objeto session o Access Token criado pelo Servidor de Autenticação existente na aplicação Web Api ( WebApiHttpClient.storeToken(tokenResponse);) e retornando a resposta enviada pela aplicação Web Api: if (response.issuccessstatuscode) string contentresponse = await response.content.readasstringasync(); return Content(contentResponse); TokenResponse tokenresponse = await response.content.readasasync<tokenresponse>(); WebApiHttpClient.storeToken(tokenResponse); return Content(tokenResponse.AccessToken); return RedirectToAction("Index", "Home"); Executar o Serviço (aplicação Web API, WebApiAuth) e o Cliente (aplicação MVC, ClienteMvcAuth). Clicar no botão Login para autenticar um utilizador Token response: "access_token":"hifwj.", "token_type":"bearer", "expires_in":1209599, "username":"a@a.pt", ".issued":"tue, 24 Nov 2015 20:41:07 GMT", ".expires":"tue, 08 Dec 2015 20:41:07 GMT"
5. Efetuar o Pedido de um Recurso protegido Na aplicação Web Api colocar a classe Editora na pasta Models. Adicionar um Controlador para o modelo Editora. Colocar o filtro [Authorize] no cabeçalho da classe EditorasController. Na aplicação Cliente MVC colocar a classe Editora na pasta Models. Adicionar um Controlador para o modelo Editora. Alterar esta classe EditorasController para fazer pedidos ao Serviço web Api. Executar o Serviço e o Cliente. Testar as várias ações do controlador Editoras do Cliente.