首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >.Net声称8月--无法设置当前主体

.Net声称8月--无法设置当前主体
EN

Stack Overflow用户
提问于 2014-02-16 05:02:02
回答 2查看 7.3K关注 0票数 7

我正在尝试重新使用基于索赔的auth登录系统。

到现在为止还好

跨过一步,它似乎正确地计算了用户名和密码,并正确地创建了索赔主体(包括添加身份验证类型,以便将IsAuthenticated设置为true,per this SO question)。

但后来..。

不知何故,身份似乎没有被正确地设定在电线上。因此,我被直接重定向回登录页面。

“守则”

我在global.asax中有以下内容

代码语言:javascript
复制
private void Application_PostAuthenticateRequest(object sender, EventArgs e)
{
    var currentPrincipal = ClaimsPrincipal.Current; 
    var transformer = new ClaimsTransformer(); //My own custom transformer; code below.
    var newPrincipal = transformer.Authenticate(string.Empty, currentPrincipal); // does the transformation

    // as I understand, it is proper & recommnded to set both of these
    Thread.CurrentPrincipal = newPrincipal;
    HttpContext.Current.User = newPrincipal;
}

在我的登录控制器中,我有一个针对成员数据库的简单测试。我在调试时验证了newCP作为一个有效的、经过身份验证的标识,该标识具有预期的名称。

代码语言:javascript
复制
[HttpPost]
[AllowAnonymous]
public ActionResult UserLogin(LoginViewModel viewModel)
{

    var loginSuccess = Membership.ValidateUser(viewModel.UserName, viewModel.Password);

    if (loginSuccess)
    {
        // CustomApplicationIdentity puts some identity-based logic into business domain terms and uses Claims underneath. 
        //Should have done it at the IPrincipal level, but instead I created the ToAuthenticatedStandardClaimsIdentity() which returns a new authenticated ClaimsIdentity.

        var newIdentity = new CustomApplicationIdentity(viewModel.UserName);
        var cp = new ClaimsPrincipal(newIdentity.ToAuthenticatedStandardClaimsIdentity());

        var newCP = new ClaimsTransformer().Authenticate(string.Empty, cp);
        System.Web.HttpContext.Current.User = newCP;
        Thread.CurrentPrincipal = newCP;

        if (!string.IsNullOrWhiteSpace(viewModel.ReturnUrl))
        {
            return Redirect(viewModel.ReturnUrl);
        }
        return RedirectToAction("Index", "Identity");

    }
}

问题

当它重定向到Action时,我看到它再次击中了Application_PostAuthenticateRequest,这是非常有意义的。

但是,尽管之前设置了主体,但现在这似乎是一个空主体(没有名称,IsAuthenticated设置为false)。

我哪里出问题了?

一些想法:

  • 是因为我还没有设置SessionSecurityToken吗?
  • 我是否完全遗漏了一些关于线程或正确设置上下文的内容?
  • 由于UserLogin方法在MVC中,我也尝试使用控制器上下文,但这似乎也不起作用。
  • 有没有可能是其他什么东西在中间搞砸了呢?
    • 读:是否有一种简单的方法来验证旧的登录系统的某些部分没有留下和玩我?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-02-16 07:22:34

经过大量的研究(并涉猎了excellent Pluralsight Course by Dominick Baier),解决方案如下:

重大的步骤/问题

  • 我没有设置会话身份验证cookie,因此重定向被视为一个新请求,它没有看到cookie,也没有设置主体。
  • 后来,当我使用会话身份验证管理器时,发现Cassini (VS内置在调试服务器中)并没有在所有的SessionAuthenticationManager上加载
    • (IIS和IIS Express做得很好)。

全解

一步一步地(同样,这大部分都归功于Dominick的视频):

步骤1:将标识服务添加到配置中

  • 右键单击项目,并选择“添加引用.”
  • 在框架部分中,选择System.IdentityModel.Services
  • 在web.config中添加以下内容:

(在下面的大纲中,在web.config中插入该大纲中的两个部分):

代码语言:javascript
复制
<configuration>
    <configSections>
        <section name="system.identityModel" type="System.IdentityModel.Configuration.SystemIdentityModelSection, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
        <section name="system.identityModel.services" type="System.IdentityModel.Services.Configuration.SystemIdentityModelServicesSection, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
    </configSections>
</configuration>

步骤2:添加会话身份验证管理器

(这取决于配置设置)

在您的system.webServer部分的web.config中,添加以下行:

代码语言:javascript
复制
  <remove name="RoleManager"/> <!--Not needed anymore in my case -->
  <add name="SessionAuthenticationModule" type="System.IdentityModel.Services.SessionAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>

步骤3:删除PostAuthenticate方法中的Global.asax

(不再需要SAM,因为SAM检测cookie;如果不必运行每个请求,为什么要运行它,对吗?)

步骤4:设置索赔转换方法以设置身份验证cookie

将这些行添加到您的ClaimsAuthenticationManager中(我的行名为ClaimsTransformer)。我把它放在一个名为"EstablishSession“的单独方法中,在它已经被转换之后,它接受了我的校长:

代码语言:javascript
复制
private void EstablishSession(ClaimsPrincipal transformedPrincipal)
{
    var sessionToken = new SessionSecurityToken(transformedPrincipal, TimeSpan.FromHours(8));
    FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie(sessionToken);
}

因此,每当您转换声明时,总是会设置cookie,这是有意义的,因为只有当用户成功地通过身份验证时,您才会转换声明。

第五步:把头发扯下来.

...wondering为什么SessionAuthenticationManager总是空的。

说真的,一切似乎都正常,你的配置是正确的,但是如果它不是空的,那就去死吧。单人。时间到了。

步骤6:将调试web服务器切换到IIS Express

啊哈,看起来卡西尼( VS中的构建)不适用于SessionAuthenticationManager。

但是,IIS Express提供。将其切换到项目设置中。

还有沃拉!

现在我有了一页有用的东西。

票数 8
EN

Stack Overflow用户

发布于 2014-02-16 05:16:02

我认为您需要实现SessionSecurityToken,或者在页面请求之间持久化会话。下面是一种更自定义的方法:

代码语言:javascript
复制
    public static int SetAuthCookie(this HttpResponseBase responseBase, User user, bool rememberMe)
    {
        // Initialize Session Ticket
        var authTicket = new FormsAuthenticationTicket(1
            , user.Email
            , DateTime.Now
            , DateTime.Now.AddHours(30)
            , rememberMe
            , JsonConvert.SerializeObject(new {
                Email = user.Email,
                FirstName = user.FirstName,
                Id = user.Id
            })
            , FormsAuthentication.FormsCookiePath);

        var encTicket = FormsAuthentication.Encrypt(authTicket);
        HttpCookie authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);

        if (authTicket.IsPersistent)
            authCookie.Expires = authTicket.Expiration;

        responseBase.Cookies.Add(authCookie);
        return encTicket.Length;
    }



    public static void VerifyAuthCookie(HttpContext context)
    {

        HttpCookie authCookie = context.Request.Cookies[FormsAuthentication.FormsCookieName];
        if (authCookie == null)
            return;

        FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
        if (authTicket == null)
            return;

        if (authTicket.Expired)
            return;

        User user = !string.IsNullOrEmpty(authTicket.UserData) ? JsonConvert.DeserializeObject<User>(authTicket.UserData) : null;
        if (user == null)
            return;

        // Create an Identity object
        UserIdentity id = new UserIdentity(user, authTicket);

        // This principal will flow throughout the request.
        GenericPrincipal principal = new GenericPrincipal(id, new [] { "User" });
        context.User = principal;

}

票数 -2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/21807535

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档