FormsAuthentication 在整个浏览器(同一台 PC 上)使用相同的票证?

发布于 2024-11-02 19:44:38 字数 4794 浏览 2 评论 0原文

我不明白 FormsAuthentication 发生了什么。当我第一次打开电脑并开始处理我的项目时,每次尝试登录时,都会收到一条错误消息,告诉我未找到查询的用户名(在我的情况下为昵称)序列。我在调试时检查它的值,结果发现它是一个空字符串(“”)。然后,如果我停止调试然后再次启动它,我会正常登录并选择正确的用户名。

此外,如果我尝试从另一个浏览器使用另一个用户登录,也会发生同样的事情,但最终它会选择使用同一浏览器登录的同一用户! FormsAuthentication 是否在所有浏览器中为所有用户使用相同的票证?我能做些什么吗?或者我在这里做错了什么......?

这是我的代码:

    [HttpPost]
    public ActionResult Login(LoginViewModel dto)
    {  
        bool flag = false;
        if (ModelState.IsValid)
        {
            if (_userService.AuthenticateUser(dto.Email, dto.Password, false))
            {
                var user = _userService.GetUserByEmail(dto.Email);

                flag = true;

                FormsAuthentication.SetAuthCookie(user.Nickname, dto.RememberMe);
            }
        }
        if (flag)
        {
            return RedirectToAction("Index", "Home");
        }
        else
        {
            ViewData.Add("InvalidLogin", "The login info you provided were incorrect.");
            return PartialView(dto);
        }
    }

    public User GetUserFromSession(bool withAllInfo)
    {
        string nickname = _httpContext.User.Identity.Name;
        IsNotNull(nickname, "session user nickname");
        var user = _userService.GetUserByNickname(nickname, withAllInfo);
        return user;
    }

    public User GetUserFromSession(string nickname, bool withAllInfo)
    {
        if (string.IsNullOrEmpty(nickname))
            return GetUserFromSession(withAllInfo);

        var user = _userService.GetUserByNickname(nickname, withAllInfo);
        return user;
    }

上面的方法位于辅助类中(它采用 HttpContext 的实例 - 使用 StructureMap)。即使我使用其他用户登录,它也会不断返回昵称为 J.Smith 的用户。有趣的是,它随后使用 Summary ActionMethod 显示正确登录的用户(见下文)。

    [Authorize]
    public ActionResult Summary()
    {
        var nickname = this.HttpContext.User.Identity.Name;
        var user = _helper.GetUserFromSession(nickname, true);
        var viewModel = Mapper.Map<User, UserInfoSummaryViewModel>(user);
        return PartialView(viewModel);
    }

此方法显示所有用户信息的摘要,包括他们的出价、列表、新消息...等。这实际上工作正常(在大多数情况下)。但问题出在 GetUserFromSession() 方法上,它把一切搞乱了。

    public ActionResult SignOut()
    {
        FormsAuthentication.SignOut();
        return RedirectToAction("Index", "Home");
    }

这就是我需要做的所有事情来注销用户并删除他们的 cookie/会话或 FormsAuthentication 来管理会话吗?

注意:我没有使用内置的 Membership API,也不想使用它。

那么,我能做些什么来解决这个烂摊子吗?

更新:

StructureMap 配置:

    private static IContainer ConfigureStructureMap()
    {

        ObjectFactory.Configure(x =>
                            {
                                x.For<IDatabaseFactory>().Use<EfDatabaseFactory>();
                                x.For<IUnitOfWork>().Use<UnitOfWork>();
                                x.For(typeof (IRepository<>)).Use(typeof (BaseRepository<>));
                                x.For<IGenericMethodsRepository>().Use<GenericMethodsRepository>();
                                x.For<IUserService>().Use<UsersManager>();
                                x.For<IBiddingService>().Use<BiddingService>();
                                x.For<ISearchService>().Use<SearchService>();
                                x.For<IFaqService>().Use<FaqService>();
                                x.For<IItemsService>().Use<ItemsService>();
                                x.For<IPrivateMessagingService>().Use<PrivateMessagingService>();
                                x.For<IStaticQueriesService>().Use<StaticQueriesService>();
                                x.For<ICommentingService>().Use<CommentingService>();
                                x.For<ICategoryService>().Use<CategoryService>();
                                x.For<IHelper>().Use<Helper>();
                                x.For<HttpContext>().Use(HttpContext.Current);

            x.For(typeof(Validator<>)).Use(typeof(NullValidator<>));

            x.For<Validator<Rating>>().Use<RatingValidator>();
            x.For<Validator<TopLevelCategory>>().Use<TopLevelCategoryValidator>();
        });

        Func<Type, IValidator> validatorFactory = type =>
        {
            var valType = typeof(Validator<>).MakeGenericType(type);
            return (IValidator)ObjectFactory.GetInstance(valType);
        };

        ObjectFactory.Configure(x => x.For<IValidationProvider>().Use(() => new ValidationProvider(validatorFactory)));
        return ObjectFactory.Container;
    }

I do not understand what's going on with FormsAuthentication. When I first turn on my PC and start working on my project, everytime I try to login, I get an error telling me that the queried username (nickname in my case) is not found the sequence. I check its value while debugging, it turns out it's a null string (""). Then if I stop debugging then start it again, I get logged in normally and it picks up the right username.

Moreover, if I try to login with another user from another browser, the same thing happens but eventually it picks up the same user that was logged in using the same browser! Does FormsAuthentication use the same ticket in all browsers, for all users? Is there anything I can do about it? Or could it be that I'm doing something wrong here...?

Here's my code:

    [HttpPost]
    public ActionResult Login(LoginViewModel dto)
    {  
        bool flag = false;
        if (ModelState.IsValid)
        {
            if (_userService.AuthenticateUser(dto.Email, dto.Password, false))
            {
                var user = _userService.GetUserByEmail(dto.Email);

                flag = true;

                FormsAuthentication.SetAuthCookie(user.Nickname, dto.RememberMe);
            }
        }
        if (flag)
        {
            return RedirectToAction("Index", "Home");
        }
        else
        {
            ViewData.Add("InvalidLogin", "The login info you provided were incorrect.");
            return PartialView(dto);
        }
    }

    public User GetUserFromSession(bool withAllInfo)
    {
        string nickname = _httpContext.User.Identity.Name;
        IsNotNull(nickname, "session user nickname");
        var user = _userService.GetUserByNickname(nickname, withAllInfo);
        return user;
    }

    public User GetUserFromSession(string nickname, bool withAllInfo)
    {
        if (string.IsNullOrEmpty(nickname))
            return GetUserFromSession(withAllInfo);

        var user = _userService.GetUserByNickname(nickname, withAllInfo);
        return user;
    }

The method above is in a helper class (which takes an instance of HttpContext - using StructureMap). It keeps returning the user with nickname J.Smith even if I logged in with another user. And the funny thing is that it then displays the correctly logged in user using the Summary ActionMethod (see below).

    [Authorize]
    public ActionResult Summary()
    {
        var nickname = this.HttpContext.User.Identity.Name;
        var user = _helper.GetUserFromSession(nickname, true);
        var viewModel = Mapper.Map<User, UserInfoSummaryViewModel>(user);
        return PartialView(viewModel);
    }

This method displays a summary of all the user's info including their bids, listings, new messages... etc. This actually works correctly (in most cases). But the problem is with the GetUserFromSession() method which is messing everything up.

    public ActionResult SignOut()
    {
        FormsAuthentication.SignOut();
        return RedirectToAction("Index", "Home");
    }

Is that all I need to do to sign the user out and delete their cookie/session or whatever FormsAuthentication does to manage sessions?

Note: I am not using the built-in Membership API and I do not want to use it.

So, is there anything I can do to fix this mess?

UPDATE:

StructureMap configuration:

    private static IContainer ConfigureStructureMap()
    {

        ObjectFactory.Configure(x =>
                            {
                                x.For<IDatabaseFactory>().Use<EfDatabaseFactory>();
                                x.For<IUnitOfWork>().Use<UnitOfWork>();
                                x.For(typeof (IRepository<>)).Use(typeof (BaseRepository<>));
                                x.For<IGenericMethodsRepository>().Use<GenericMethodsRepository>();
                                x.For<IUserService>().Use<UsersManager>();
                                x.For<IBiddingService>().Use<BiddingService>();
                                x.For<ISearchService>().Use<SearchService>();
                                x.For<IFaqService>().Use<FaqService>();
                                x.For<IItemsService>().Use<ItemsService>();
                                x.For<IPrivateMessagingService>().Use<PrivateMessagingService>();
                                x.For<IStaticQueriesService>().Use<StaticQueriesService>();
                                x.For<ICommentingService>().Use<CommentingService>();
                                x.For<ICategoryService>().Use<CategoryService>();
                                x.For<IHelper>().Use<Helper>();
                                x.For<HttpContext>().Use(HttpContext.Current);

            x.For(typeof(Validator<>)).Use(typeof(NullValidator<>));

            x.For<Validator<Rating>>().Use<RatingValidator>();
            x.For<Validator<TopLevelCategory>>().Use<TopLevelCategoryValidator>();
        });

        Func<Type, IValidator> validatorFactory = type =>
        {
            var valType = typeof(Validator<>).MakeGenericType(type);
            return (IValidator)ObjectFactory.GetInstance(valType);
        };

        ObjectFactory.Configure(x => x.For<IValidationProvider>().Use(() => new ValidationProvider(validatorFactory)));
        return ObjectFactory.Container;
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

只怪假的太真实 2024-11-09 19:44:38

您可以编写一个仅返回当前 HttpContext.Current 实例的 HttpContext 提供程序类(接口)。

using System.Web;

interface IHttpContextProvider
{
    HttpContextBase HttpContext { get; }
}

public class HttpContextProvider : IHttpContextProvider
{
    HttpContextBase HttpContext
    {
        get
        {
            return new HttpContextWrapper(System.Web.HttpContext.Current);
        }
    }
}

You could write a HttpContext provider class (interface) that just returns the current HttpContext.Current instance.

using System.Web;

interface IHttpContextProvider
{
    HttpContextBase HttpContext { get; }
}

public class HttpContextProvider : IHttpContextProvider
{
    HttpContextBase HttpContext
    {
        get
        {
            return new HttpContextWrapper(System.Web.HttpContext.Current);
        }
    }
}
女中豪杰 2024-11-09 19:44:38

听起来由 StructureMap 维护/创建的 _httpContext 实例的范围不正确。 这里有关范围的更多信息 - 如果您愿意,我很乐意进一步研究它发布您的 StructureMap 注册码。

It sounds like the scope fo the _httpContext instance being maintained/created by StrucutureMap is incorrect. Here's some more information on scope--I'd be happy to look into it further if you want to post your StrucutureMap registration code.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文