MVC 5如何用本地化路线定义Owin LoginPath

我有一个MVC 5网站与本地化的路线定义为

routes.MapRoute( name: "Default", url: "{culture}/{controller}/{action}/{id}", defaults: new { culture = CultureHelper.GetDefaultCulture(), controller = "Home", action = "Index", id = UrlParameter.Optional } ); 

默认文化的结果是"en-US"


问题出现在启动时,我必须使用LoginPath属性定义loginURL,该属性被设置一次,它将始终使用提供的值,例如,如果“/ en-Us / Account / Login”是指定值。 然后我尝试着使用UrlHelper类来体验一些魔法的希望,但是结果显然是一样的:

 var httpContext = HttpContext.Current; if (httpContext == null) { var request = new HttpRequest("/", "http://example.com", ""); var response = new HttpResponse(new StringWriter()); httpContext = new HttpContext(request, response); } var httpContextBase = new HttpContextWrapper(httpContext); var routeData = new RouteData(); var requestContext = new RequestContext(httpContextBase, routeData); UrlHelper helper = new UrlHelper(requestContext); var loginPath = helper.Action("Login", "Account"); // Enable the application to use a cookie to store information for the signed in user app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, LoginPath = new PathString(loginPath) }); 

我的问题是:是否有办法破解这个机制来dynamic检索当前的文化,或者我被迫设置当前文化到一个cookie,当我redirect到login页面,使用cookie值设置当前渲染页面之前的文化?

谢谢

我完全有同样的问题,并找出了克服这个限制的方法。

CookieAuthenticationOptions选项中,有一个“提供者”属性,它使用CookieAuthenticationProvider进行初始化。 这实现了一个名为ApplyRedirect的方法和一个委托OnApplyRedirect 。 我的第一个想法是覆盖这个ApplyRedirect并实现所需的逻辑来处理本地化的路线。 但不幸的是,它不能被覆盖。 将我的逻辑传递给OnApplyRedirect会导致覆盖默认行为。 理论上你可以抓住这个行为的源头,把它复制到你的项目中并根据你的需要进行修改,但这显然不是一个好的做法。 首先,我决定用两个使用委托的扩展点对CookieAuthenticationProvider进行封装,并保留默认行为,除了使用的URL或更容易的解决方法(thx to lafi)。

然后在身份validationconfiguration中,我将自定义逻辑添加到提供程序中:

 public void ConfigureAuth(IAppBuilder app) { UrlHelper url = new UrlHelper(HttpContext.Current.Request.RequestContext); CookieAuthenticationProvider provider = new CookieAuthenticationProvider(); var originalHandler = provider.OnApplyRedirect; //Our logic to dynamically modify the path (maybe needs some fine tuning) provider.OnApplyRedirect = context => { var mvcContext = new HttpContextWrapper(HttpContext.Current); var routeData = RouteTable.Routes.GetRouteData(mvcContext); //Get the current language RouteValueDictionary routeValues = new RouteValueDictionary(); routeValues.Add("lang", routeData.Values["lang"]); //Reuse the RetrunUrl Uri uri = new Uri(context.RedirectUri); string returnUrl = HttpUtility.ParseQueryString(uri.Query)[context.Options.ReturnUrlParameter]; routeValues.Add(context.Options.ReturnUrlParameter, returnUrl); //Overwrite the redirection uri context.RedirectUri = url.Action("login", "account", routeValues); originalHandler.Invoke(context); }; app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, LoginPath = new PathString(url.Action("login", "account")), //Set the Provider Provider = provider }); } 

另请参阅以下代码:

  • CookieAuthenticationHandler
  • CookieAuthenticationProvider

希望它适合您的需求。

更新:为了减less混淆,我更新了我的答案,使用@Lafis增强function,而不是使用包装类来应用扩展行为。 upvoting时也请注意@Lafis。

要增强@martinoss答案,您可能会达到相同的结果,而不实施一个包装。 只需复制原始处理程序,分配一个实现redirect逻辑的新处理程序来修改context.RedirectionUri ,并在最后调用原始处理程序。

 CookieAuthenticationProvider provider = new CookieAuthenticationProvider(); var originalHandler = provider.OnApplyRedirect; provider.OnApplyRedirect = context => { //insert your logic here to generate the redirection URI string NewURI = "...."; //Overwrite the redirection uri context.RedirectUri = NewURI; originalHandler.Invoke(context); }; app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, LoginPath = new PathString(url.Action("Login", "Account")), Provider = provider }); 

这个怎么样:

 var cao = new CookieAuthenticationOptions { AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, LoginPath = new PathString("/Account/Login"), Provider = new CookieAuthenticationProvider { OnApplyRedirect = ApplyRedirect } }; app.UseCookieAuthentication(cao); 

  private static void ApplyRedirect(CookieApplyRedirectContext context) { UrlHelper _url = new UrlHelper(HttpContext.Current.Request.RequestContext); String actionUri = _url.Action("Login", "Account", new { }); context.Response.Redirect(actionUri); } 

没有太多的URL格式等责任,你可以做下面的事情

 public static void Configuration(IAppBuilder app) { UrlHelper url = new UrlHelper(HttpContext.Current.Request.RequestContext); app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, LoginPath = new PathString(url.Action("LogOn", "Account", new { area = "Account" })), Provider = new CookieAuthenticationProvider { OnApplyRedirect = context => context.Response.Redirect(context.RedirectUri.Replace(CultureHelper.GetDefaultCulture(), Thread.CurrentUiCulture.Name)) } }); } 

我改进了哨兵答案,保持返回url:

 private static void ApplyRedirect(CookieApplyRedirectContext context) { //use this way to keep return url var loginUrl = context.RedirectUri.Insert( context.RedirectUri.IndexOf("/Account/Login"), "/" + CultureHelper.GetCurrentCulture()); context.Response.Redirect(loginUrl); } 

我认为我在这个答案的晚了一年,但这里的主要目标是分享知识… 🙂

我刚刚在一个现在正在开发的应用程序中发现了同样的问题。 我研究了我们需要的代码量(在之前的文章中)来解决这个问题,我很担心(大部分代码是复杂的,碰到了兽的内部)。 所以我试图find一个更简单的解决scheme,我所做的是添加以下路由到我的路线集合:

 routes.MapRoute( name: "loginRoute", url: "account/login", defaults:new { culture = "", controller = "account", action = "login", id = UrlParameter.Optional }); 

这将允许我的帐户控制器中的login操作被调用,并且我的标准机制(从Controller的BeginExecuteCore方法覆盖)能够将当前的UI文化附加到URL。

我希望它可以帮助别人。

新增:我的标准机制:

 protected override IAsyncResult BeginExecuteCore(AsyncCallback callback, object state) { var cultureName = RouteData.Values["culture"] as string; var cultureCookie = Request.Cookies["_culture"]; if (cultureCookie != null && string.IsNullOrEmpty(cultureName)) { cultureName = cultureCookie.Value; } if (cultureName == null) cultureName = Request.UserLanguages != null && Request.UserLanguages.Length > 0 ? Request.UserLanguages[0] : null; cultureName = CultureHelper.GetImplementedCulture(cultureName); if (RouteData.Values["culture"] as string != cultureName) { RouteData.Values["culture"] = cultureName.ToLowerInvariant(); // lower case too var cookie = Request.Cookies["_culture"]; if (cookie != null) cookie.Value = cultureName; // update cookie value else { cookie = new HttpCookie("_culture") { Value = cultureName, Expires = DateTime.Now.AddYears(1) }; } Response.Cookies.Add(cookie); // Redirect user Response.RedirectToRoute(RouteData.Values); } Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(cultureName); Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture; return base.BeginExecuteCore(callback, state); } 

我发现更简单的方法:

 UrlHelper _url = new UrlHelper(HttpContext.Current.Request.RequestContext); public void ConfigureAuth(IAppBuilder app) { String actionUri = _url.Action("Login", "Account", new { }); String unescapeActionUri = System.Uri.UnescapeDataString(actionUri); app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, LoginPath = new PathString(unescapeActionUri) }); [...]