ASP.NET MVC5路由问题



所以,我有一个MVC5站点,它使用默认的路由模板{controller}/{action}/{id},这很好。网站中的大多数内容都需要登录(即几乎所有地方都使用[Authorize]属性(,这很好。

现在,当使用某种链接模式时,我需要允许匿名访问来选择页面:App/{token}/{action}。{token}是一个随机字符串,与我的数据库中的某个内容相关联。我可以随意发布和停用这些代币。

我通过实现一个自定义的RouteBase来解析这些令牌的传入URL,并将令牌值添加到RouteData.DataTokens中,从而使我的App控制器可以使用它,而不需要显式的操作参数,我将这个新路由添加到默认路由的前面的路由表中,如下所示:

// new route here
routes.Add("AppToken", new AnonAppAccessRoute());           
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);

问题是:添加这个now路由现在已经使我的默认路由停止工作——所有的东西现在都通过AnonAppAccessRoute,当然这只适用于少数事情。我不知道如何使我的AnonAppAccessRoute仅适用于具有特定模式的URL。MapRoute方法接受URL模式,但Add创建路由似乎不允许对其进行筛选。我缺少什么?我查阅了很多关于路由的博客和文档,但没有找到关于使用DataTokens集合的好信息(我觉得这对我的方法很重要(,也没有看到Add显式调用路由与调用MapRoute之间的区别的好解释。

这是我的自定义RouteBase:的代码

public class AnonAppAccessRoute : RouteBase
{
public override RouteData GetRouteData(HttpContextBase httpContext)
{
RouteData result = null;
string[] pathElements = httpContext.Request.Path.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
if (pathElements.Length > 0)
{
string token = TryGetArrayElement(pathElements, 1);
if (!string.IsNullOrEmpty(token))
{
result = new RouteData(this, new MvcRouteHandler());
result.DataTokens.Add("appToken", token);
result.Values.Add("controller", "App");
result.Values.Add("action", TryGetArrayElement(pathElements, 2, "Index"));
}
}
return result;
}
private string TryGetArrayElement(string[] array, int index, string defaultValue = null)
{
try
{
return array[index];
}
catch
{
return defaultValue;
}
}
public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{
return null;
}
}

我删除了自定义RouteBase,改为使用MapRoute调用,如下所示:

routes.MapRoute(
name: "AppAnon",
url: "App/{token}/{action}",
defaults: new { controller = "App", action = "Index" }
);

然后,在我的App控制器中,我在Initialize超驰:中这样做

protected AppToken _appToken = null;
protected override void Initialize(RequestContext requestContext)
{
base.Initialize(requestContext);
string token = requestContext.RouteData.Values["token"]?.ToString();
_appToken = Db.FindWhere<AppToken>("[Token]=@token", new { token });
if (!_appToken?.IsActive ?? false) throw new Exception("The token is not found or inactive.");
}

这样,我的"令牌"可以通过_appToken变量用于所有控制器操作,并且已经验证。我不需要使用RouteData.DataTokens。请注意,我的Db.FindWhere语句是ORM特定的,与这个问题并没有真正的关系——它只是我查找数据库记录的方式。

最新更新