如何改变路由的用户名登录后? [英] How to change route to username after logged in?

查看:118
本文介绍了如何改变路由的用户名登录后?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

用户登录之前,该路线是:

 本地主机:54274 /首页
本地主机:54274 /首页/
本地主机:54274 /首页/联系我们
本地主机:54274 /主页/登录
本地主机:54274 /首页/注册

在用户登录后,该航线是:

  1。本地主机:54274 /项目
2.本地主机:54274 /项目/创建
3.本地主机:54274 /项目/编辑/ 1
4.本地主机:54274 /项目/删除/ 2
5.本地主机:54274 /项目/ 1 /需求
6.本地主机:54274 /项目/ 1 /需求/创建
7.本地主机:54274 /项目/ 1 /需求/编辑/ 3
8.本地主机:54274 /项目/ 1 /需求/删除/ 4

我要的路线更改为用户名用户登录一次后,例如,用户名是hendyharf。

  1。本地主机:54274 / hendyharf /项目
2.本地主机:54274 / hendyharf /项目/创建
3.本地主机:54274 / hendyharf /项目/编辑/ 1
4.本地主机:54274 / hendyharf /项目/删除/ 2
5.本地主机:54274 / hendyharf /项目/ 1 /需求
6.本地主机:54274 / hendyharf /项目/ 1 /需求/创建
7.本地主机:54274 / hendyharf /项目/ 1 /需求/编辑/ 3
8.本地主机:54274 / hendyharf /项目/ 1 /需求/删除/ 4

我的项目控制器只有3个控制器:的HomeController ProjectController RequirementController

我的 RouteConfig.cs 仍处于默认

 公共静态无效的RegisterRoutes(RouteCollection路线)
{
    routes.IgnoreRoute({}资源个.axd / {*} PATHINFO);    routes.MapRoute(
        名称:默认,
        网址:{控制器} / {行动} / {ID}
        默认:新{控制器=家,行动=索引,ID = UrlParameter.Optional}
        );
    }
}

我应该如何做才能让路线更改用户名?


解决方案

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

 公共静态无效的RegisterRoutes(RouteCollection路线)
{
    routes.IgnoreRoute({}资源个.axd / {*} PATHINFO);    routes.MapRoute(
        名称:Username_Default
        网址:{用户名} / {控制器} / {行动} / {ID}
        默认:新{控制器=家,行动=索引,ID = UrlParameter.Optional},
        限制:新{用户名=新OwinUsernameConstraint()}
    );    routes.MapRoute(
        名称:默认,
        网址:{控制器} / {行动} / {ID}
        默认:新{控制器=家,行动=索引,ID = UrlParameter.Optional}
    );
}

但对于工作的权利,你要么需要一个字符串添加到您的网址识别段的用户名(即用户名 - {用户名} \\ )或则需要使一个约束,只允许那些在数据库中的用户名。这里是后者的一个示例:

 使用MvcUsernameInUrl.Models;
使用系统;
使用System.Collections.Generic;
使用System.Globalization;
使用System.Linq的;
使用的System.Web;
使用System.Web.Caching;
使用System.Web.Routing;命名空间MvcUsernameInUrl
{
    公共类OwinUsernameConstraint:IRouteConstraint
    {
        私有对象的SyncLock =新的对象();        公共BOOL匹配(HttpContextBase HttpContext的,路由路径,字符串参数名称,RouteValueDictionary价值,RouteDirection routeDirection)
        {
            如果(参数名称== NULL)
                抛出新的ArgumentNullException(参数名称);
            如果(价值== NULL)
                抛出新的ArgumentNullException(值);            对象值;
            如果(values​​.TryGetValue(参数名称,超时值)及和放大器;!值= NULL)
            {
                字符串的valueString = Convert.ToString(值,CultureInfo.InvariantCulture);
                返回this.GetUsernameList(HttpContext的)。载有(的valueString);
            }
            返回false;
        }        私人的IEnumerable<串GT; GetUsernameList(HttpContextBase的HttpContext)
        {
            字符串键=UsernameConstraint.GetUsernameList;
            VAR用户名= httpContext.Cache [关键]
            如果(用户名== NULL)
            {
                锁(为SyncLock)
                {
                    用户名= httpContext.Cache [关键]
                    如果(用户名== NULL)
                    {
                        //从数据库中检索用户名列表
                        使用(VAR DB = ApplicationDbContext.Create())
                        {
                            用户名=(从db.Users用户
                                            选择users.UserName).ToList();
                        }                        httpContext.Cache.Insert(
                            键:键,
                            值:用户名,
                            依赖关系:空,
                            absoluteExpiration:Cache.NoAbsoluteExpiration,
                            slidingExpiration:TimeSpan.FromSeconds(15),
                            优先级:CacheItemPriority.NotRemovable,
                            onRemoveCallback:NULL);
                    }
                }
            }            返回(IEnumerable的<串GT;)的用户名;
        }
    }
}


  

注意:我强烈建议使用这个缓存作为例子,因为路由约束上的每个的要求运行,这是不好打的数据库在每次请求。这种方法的缺点是,它需要长达15秒,在注册后的用户名变得活跃。你可能会解决这个问题,通过更新缓存(在一个线程安全的方式),当一个新的帐户,除了注册到添加记录到数据库中,这将使其在路由约束立即可用。


然后是简单地做302重定向的问题时,用户登录你可能会做一个的全局过滤

 使用的System.Web;
使用System.Web.Mvc;命名空间MvcUsernameInUrl
{
    公共类RedirectLoggedOnUserFilter:IActionFilter
    {
        公共无效OnActionExecuting(ActionExecutingContext filterContext)
        {
            VAR routeValues​​ = filterContext.RequestContext.RouteData.Values​​;
            布尔isLoggedIn = filterContext.HttpContext.User.Identity.IsAuthenticated;
            布尔requestHasUserName = routeValues​​.ContainsKey(用户名);            如果(isLoggedIn&安培;&安培;!requestHasUserName)
            {
                VAR的userName = filterContext.HttpContext.User.Identity.Name;
                //添加用户名作为路由值
                routeValues​​.Add(用户名,用户名);                filterContext.Result =新RedirectToRouteResult(routeValues​​);
            }
            否则,如果(isLoggedIn&安培;!&安培; requestHasUserName)
            {
                //作为路由值中删除用户名
                routeValues​​.Remove(用户名);                filterContext.Result =新RedirectToRouteResult(routeValues​​);
            }
        }        公共无效OnActionExecuted(ActionExecutedContext filterContext)
        {
            // 没做什么
        }
    }
}

用法

 公共类一个FilterConfig
{
    公共静态无效RegisterGlobalFilters(GlobalFilterCollection过滤器)
    {
        filters.Add(新RedirectLoggedOnUserFilter());
        filters.Add(新HandleErrorAttribute());
    }
}

MVC将时href=\"https://aspnetwebstack.$c$cplex.com/workitem/1346\" rel=\"nofollow\">自动从请求重用路由值,所以有无需更改任何 ActionLinks 包括用户名

下面是使用MVC5,OWIN和ASP.NET身份在GitHub上一个工作演示

Before user login, the route is:

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

Once after user logged in, the route is:

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

I want the route changed to the username once after user logged in. For example, the username is 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

The controller for my project are only 3 controllers: HomeController, ProjectController, and RequirementController

My RouteConfig.cs is still in a default

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 }
        );
    }
}

How should I supposed to do to make the route change to username?

解决方案

You need to add a route to cover the case that has a user name.

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 }
    );
}

But for that to work right, you will either need to add a literal string to your URL to identify the segment as username (i.e. username-{username}\) or you will need to make a constraint that only allows the user names that are in the database. Here is an example of the latter:

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;
        }
    }
}

NOTE: I strongly recommend using caching for this as in the example, since route constraints run on every request and it is not good to hit the database on every request. The downside of this is that it takes up to 15 seconds for the username to become active after it is registered. You could potentially get around this by updating the cache (in a thread-safe way) when a new account is registered in addition to adding the record to the database, which would make it available immediately in the route constraint.

Then it is simply a matter of doing a 302 redirect when the user logs in. You could potentially do that in a 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
        }
    }
}

Usage

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new RedirectLoggedOnUserFilter());
        filters.Add(new HandleErrorAttribute());
    }
}

MVC will automatically reuse route values from the request when genrating URLs, so there is no need to change any of your ActionLinks to include username.

Here is a working demo on GitHub using MVC5, OWIN, and ASP.NET Identity.

这篇关于如何改变路由的用户名登录后?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆