登录后如何更改路由到用户名?

Posted

技术标签:

【中文标题】登录后如何更改路由到用户名?【英文标题】:How to change route to username after logged in? 【发布时间】:2016-08-28 00:28:35 【问题描述】:

用户登录前,路由为:

localhost:54274/Home
localhost:54274/Home/About
localhost:54274/Home/Contact
localhost:54274/Home/Login
localhost:54274/Home/Register

用户登录后,路由为:

1. localhost:54274/Project
2. localhost:54274/Project/Create
3. localhost:54274/Project/Edit/1
4. localhost:54274/Project/Delete/2
5. localhost:54274/Project/1/Requirement
6. localhost:54274/Project/1/Requirement/Create
7. localhost:54274/Project/1/Requirement/Edit/3
8. localhost:54274/Project/1/Requirement/Delete/4

我希望在用户登录后将路由更改为用户名。例如,用户名是hendyharf。

1. localhost:54274/hendyharf/Project
2. localhost:54274/hendyharf/Project/Create
3. localhost:54274/hendyharf/Project/Edit/1
4. localhost:54274/hendyharf/Project/Delete/2
5. localhost:54274/hendyharf/Project/1/Requirement
6. localhost:54274/hendyharf/Project/1/Requirement/Create
7. localhost:54274/hendyharf/Project/1/Requirement/Edit/3
8. localhost:54274/hendyharf/Project/1/Requirement/Delete/4

我项目的控制器只有 3 个控制器:HomeControllerProjectControllerRequirementController

我的RouteConfig.cs 仍处于默认状态

public static void RegisterRoutes(RouteCollection routes)

    routes.IgnoreRoute("resource.axd/*pathInfo");

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

我应该怎么做才能将路由更改为用户名?

【问题讨论】:

您可以使用属性路由而不是传统路由exceptionnotfound.net/attribute-routing-vs-convention-routing @AbbasGaliyakot 你能给我一些关于我的问题的小例子吗? 对于从 5 开始编号的路线,为什么会有 /Project/1/ ?因为它的需求控制器,它应该没有 /Project/1/ 。有任何理由为路由和数字“1”设置 2 个控制器名称? @KarthikMR 哦,是的,我想像 Windows 中的目录一样创建路由,例如 C:/Program Files/Microsoft/... 所以我的意思是,在 1 号路由上,它将是项目的查看页面列表,一旦您单击项目,它将引导您到名为 Requirement 的页面,并且还会有一个需求列表,您可以做一些 CRUD 的事情 【参考方案1】:

你需要添加一个路由来覆盖有用户名的情况。

public static void RegisterRoutes(RouteCollection routes)

    routes.IgnoreRoute("resource.axd/*pathInfo");

    routes.MapRoute(
        name: "Username_Default",
        url: "username/controller/action/id",
        defaults: new  controller = "Home", action = "Index", id = UrlParameter.Optional ,
        constraints: new  username = new OwinUsernameConstraint() 
    );

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

但要使其正常工作,您需要在 URL 中添加一个文字字符串以将段标识为用户名(即username-username\),或者您需要制定一个仅允许以下用户名的约束在数据库中。这是后者的一个例子:

using MvcUsernameInUrl.Models;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Web;
using System.Web.Caching;
using System.Web.Routing;

namespace MvcUsernameInUrl

    public class OwinUsernameConstraint : IRouteConstraint
    
        private object synclock = new object();

        public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
        
            if (parameterName == null)
                throw new ArgumentNullException("parameterName");
            if (values == null)
                throw new ArgumentNullException("values");

            object value;
            if (values.TryGetValue(parameterName, out value) && value != null)
            
                string valueString = Convert.ToString(value, CultureInfo.InvariantCulture);
                return this.GetUsernameList(httpContext).Contains(valueString);
            
            return false;
        

        private IEnumerable<string> GetUsernameList(HttpContextBase httpContext)
        
            string key = "UsernameConstraint.GetUsernameList";
            var usernames = httpContext.Cache[key];
            if (usernames == null)
            
                lock (synclock)
                
                    usernames = httpContext.Cache[key];
                    if (usernames == null)
                    
                        // Retrieve the list of usernames from the database
                        using (var db = ApplicationDbContext.Create())
                        
                            usernames = (from users in db.Users
                                            select users.UserName).ToList();
                        

                        httpContext.Cache.Insert(
                            key: key,
                            value: usernames,
                            dependencies: null,
                            absoluteExpiration: Cache.NoAbsoluteExpiration,
                            slidingExpiration: TimeSpan.FromSeconds(15),
                            priority: CacheItemPriority.NotRemovable,
                            onRemoveCallback: null);
                    
                
            

            return (IEnumerable<string>)usernames;
        
    

注意:我强烈建议在示例中为此使用缓存,因为路由约束在每个请求上运行,并且在每个请求上都访问数据库并不好.这样做的缺点是用户名在注册后最多需要 15 秒才能激活。除了将记录添加到数据库之外,您还可以通过在注册新帐户时更新缓存(以线程安全的方式)来解决此问题,这将使其在路由约束中立即可用。

然后,只需在用户登录时执行 302 重定向即可。您可以在 global filter 中执行此操作。

using System.Web;
using System.Web.Mvc;

namespace MvcUsernameInUrl

    public class RedirectLoggedOnUserFilter : IActionFilter
    
        public void OnActionExecuting(ActionExecutingContext filterContext)
        
            var routeValues = filterContext.RequestContext.RouteData.Values;
            bool isLoggedIn = filterContext.HttpContext.User.Identity.IsAuthenticated;
            bool requestHasUserName = routeValues.ContainsKey("username");

            if (isLoggedIn && !requestHasUserName)
            
                var userName = filterContext.HttpContext.User.Identity.Name;
                // Add the user name as a route value
                routeValues.Add("username", userName);

                filterContext.Result = new RedirectToRouteResult(routeValues);
            
            else if (!isLoggedIn && requestHasUserName)
            
                // Remove the user name as a route value
                routeValues.Remove("username");

                filterContext.Result = new RedirectToRouteResult(routeValues);
            
        

        public void OnActionExecuted(ActionExecutedContext filterContext)
        
            // Do nothing
        
    

用法

public class FilterConfig

    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    
        filters.Add(new RedirectLoggedOnUserFilter());
        filters.Add(new HandleErrorAttribute());
    

MVC 将automatically reuse route values from the request when genrating URLs,因此无需更改您的任何ActionLinks 以包含username

Here is a working demo 在 GitHub 上使用 MVC5、OWIN 和 ASP.NET Identity。

【讨论】:

我很抱歉我的新问题,我忘了在这个问题中改进我的细节,所以我决定创建一个新问题。但无论如何,非常感谢您提供非常详细的答案!这真的很有帮助!对不起,我是 *** 的新手,所以我现在才打开 ***

以上是关于登录后如何更改路由到用户名?的主要内容,如果未能解决你的问题,请参考以下文章

正确登录后如何重定向用户?

从 Vuex 动作和组件更改路由

在用户登录页面后添加路由

更改 Laravel 中的默认登录路由

如果用户已登录,则更改路由名称和组件

Laravel 5.5登录后重定向到特定路由