Desenvolvimento - ASP. NET
Trabalhando com Limites de Rotas (Route Constraints) no ASP.NET MVC
Em aplicações Web é normal a necessidade de restringir o acesso à uma determinada URL para um usuário não autenticado por exemplo. Neste artigo, veremos como fazer este tipo de restrição (Route Constraints), bem como a restrição do roteamento de URLs cujo parâmetro não atenda os requisitos especificados (Via Regular Expressions).
por André BaltieriIntrodução
Utiliza-se limites de rotas para restringir o browser a na requisição de uma rota.
Podemos utilizar regular expressions para restringir uma rota.
Para melhor entender, vamos tomar como base a seguinte rota customizada, mostrada na Listagem 1.
1: routes.MapRoute(
2: "Product", // Route name
3: "Product/{productId}", // URL with parameters
4: new { controller = "Product", action = "Detail" } // Parameter defaults
5: );
Listagem 1 – Rota customizada para Produtos.
O Controller Product é mostrado na Listagem 2.
1: using System.Collections.Generic;
2: using System.Linq;
3: using System.Web.Mvc;
4: using LimitesDeRotas.Models;
5:
6: namespace LimitesDeRotas.Controllers
7: {
8: public class ProductController : Controller
9: {
10: List<Product> produtos = new List<Product>{
11: new Product{ Id=1, Title="Pasta" },
12: new Product{ Id=2, Title="Rice" },
13: new Product{ Id=3, Title="Beans" }
14: };
15:
16: //
17: // GET: /Product/
18: public ActionResult Index()
19: {
20: return View();
21: }
22:
23: public ActionResult Detail(int productId)
24: {
25: Product prod = (from p in produtos where p.Id == productId select p).First<Product>();
26: return View(prod);
27: }
28: }
29: }
Listagem 2 – Controller ProductController.cs.
Note que a ação Details() do controller ProductController aceita um parâmetro único chamado productId, do tipo inteiro.
A rota customizada Product que criamos aceita as seguintes URLs:
· /Product/23
· /Product/7
Mas infelizmente, também aceita as seguintes URLs:
· /Product/blah
· /Product/wrong
Qualquer requisição cujo parâmetro não seja inteiro, causará um erro. O correto a se fazer é rotear apenas URLs que contenham o parâmetro productId como inteiro.
Para isso, utilizaremos um limite de rota (Route Constraint) na criação da rota para restringir URLs.
A Listagem 3 mostra a mesma rota (Product) porém, com um limite (Utilizando regular expressions) para informar que apenas valores numéricos no parâmetro productId serão rotados.
1: routes.MapRoute(
2: "Product", // Route name
3: "Product/{productId}", // URL with parameters
4: new { controller = "Product", action = "Detail" }, // Parameter defaults
5: new { productId = @"\d+" }
6: );
Listagem 3 – Rota customizada com limite.
Note que apenas adicionamos um parâmetro a mais (new { productId = @"\d+" }), que possui um regular expression, e este diz que podemos ter infinitos caracteres, desde que sejam numéricos.
A expressão regular \d+ roteia URLs cujo parâmetro tenha 1 ou mais inteiros, o que implica no roteamento das seguintes URLs:
· /Product/7
· /Product/2010
Mas NÃO no roteamento das URLs:
· /Product/learnmvc
· /Product/test
· /Product
Estas requisições serão manipuladas por outra rota ou, se não encontrar nenhuma rota exibirá o erro “The resource could not be found“.
Desta mesma forma, podemos utilizar regular expressions para validar E-mails, como mostrado na Listagem 4.
1: routes.MapRoute(
2: "User", // Route name
3: "User/{email}", // URL with parameters
4: new { controller = "User", action = "Detail" }, // Parameter defaults
5: new { email = @"^[\w\.=-]+@[\w\.-]+\.[\w]{2,3}$", isLocal = new LocalhostConstraint() }
6: );
Listagem 4 – Limite que aceita apenas E-mails como parâmetro.
Limites de Rotas Customizadas
Um limite de rota personalizada permite a prevenção de uma rota ser mapeada a menos que a condição customizada seja a rota requisitada.
Para isto, basta implementar a interface IRouteConstraint, que contém apenas um método:
1: bool Match(
2: HttpContextBase httpContext,
3: Route route,
4: string parameterName,
5: RouteValueDictionary values,
6: RouteDirection routeDirection )
O método retorna um valor Booleano. Se retornar false, a rota associada com o limite não combina com a requisição do browser.
AListagem 5, contém um exemplo da criação de uma constraint.
1: using System.Web;
2: using System.Web.Routing;
3:
4: namespace LimitesDeRotas.Contraints
5: {
6: public class RequireAuthConstraint : IRouteConstraint
7: {
8: public bool Match(
9: HttpContextBase httpContext,
10: Route route,
11: string parameterName,
12: RouteValueDictionary values,
13: RouteDirection routeDirection)
14: {
15: return httpContext.Request.IsAuthenticated;
16: }
17: }
18: }
Listagem 5– Constraint para proibir acesso de usuários não autenticados.
Nota: Para esta constraint, criei uma nova pasta na raiz da aplicação com o nome “Constraints” e criei o arquivo da Listagem 5 com o nome RequireAuthConstraint.cs.
Com o limite criado, podemos utilizá-lo no Global.asax como fizemos previamente com os regular expressions. Veja na Listagem 6.
1: routes.MapRoute(
2: "Product", // Route name
3: "Product/{productId}", // URL with parameters
4: new { controller = "Product", action = "Detail" }, // Parameter defaults
5: new { isLocal = new RequireAuthConstraint(), productId = @"\d+" }
6: );
Listagem 6– Limite de rota customizado para acesso somente de usuários logados.
Estes limites continuam definidos dentro do Global.asax. No exemplo, utilizamos um limites que não permite requisições a página Product sem o usuário estar logado.
Por exemplo, o URL /Product/Detail irá falhar caso o usuário não esteja logado. Podemos ter mais de um limite, como no caso, ainda temos o limite para aceitar somente parâmetros numéricos no productId (Separado por vírgula).
É importante notar que outras rotas definidas no Global.asax podem servir para a mesma requisição. Um limite previne uma rota em particular de ser comparada a requisição, mas não todas as rotas definidas no Global.asax.
Sendo assim, as outras rotasdevem estarcomentadas, ou conter o mesmo limite,pois caso contrário, a mesma conseguiria manipular requisições para o controller.
Conclusão
Limites de rotas nos permitir ter o controle de quais rotas devemos rotear ou não. Além disso, podemos utilizar estes limites para negar acesso de usuários não autenticados, por exemplo.
Referências
ASP.NET MVC
http://www.asp.net/mvc
Até o próximo artigo!