将角色分配给匿名会话

时间:2014-03-10 20:10:34

标签: asp.net webforms roleprovider

我们的网站使用ASP角色和成员资格提供程序系统进行表单身份验证。我们已将文件组织到文件夹中,这些文件夹通过文件夹web.config文档强制执行授权列表(例如:您必须具有Admin角色才能访问〜/ Admin文件夹中的页面)并且我们不允许匿名(未登录)访问除了站点根目录。站点在IIS7.5上托管,带有.Net 4.0绑定和脚本映射。

利益相关方现在要求我们允许PIN针对特定用例进行身份验证,用户尚未拥有凭据,但已收到带PIN的信件。

我们编写了一个堆栈来验证用于身份验证的PIN,但我们没有办法告诉他们会员/角色API他们现在是登录用户,因为他们使用PIN绕过我们的SSO。

当操作员提供有效的引脚时,我需要找到一种临时为匿名会话分配角色的方法,这样他们就可以利用文件夹中不允许匿名访问的页面。

我已经看到有迹象表明您可以将个人资料信息与匿名用户联系起来,但我一直无法找到有关为用户(会话确实)分配角色的任何信息。

是否有人有任何想法为匿名用户分配角色,以便他们可以浏览需要特定角色的授权列表?

2 个答案:

答案 0 :(得分:1)

尝试扩展ClaimsAuthenticationManager。您可以覆盖Authenticate。这应该允许您将您的PIN用户视为经过身份验证,并允许您分配角色。

public class ClaimsTransformer : ClaimsAuthenticationManager
{
    public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal)
    {...

您可以在ClaimsAuthenticationManager(或Global.asax.cs)中激活展开的.vb。此示例来自ASP.NET MVC应用程序。 (你没有提到你是使用MVC还是WebForms。)

public class MvcApplication : System.Web.HttpApplication
{

    ...

    protected void Application_PostAuthenticateRequest()
    {
        var principal = ClaimsPrincipal.Current;
        var transformer = new ClaimsTransformer();

        var newPrincipal = transformer.Authenticate(string.Empty, principal);

        Thread.CurrentPrincipal = newPrincipal;
        HttpContext.Current.User = newPrincipal;
    }
}

答案 1 :(得分:1)

弗兰克,

以下是我在一家不再工作的公司使用的一段代码。

首先,这是一个常量和私有变量列表:

private const int LOGON_PROVIDER_DEFAULT = 0;
private const int LOGON_LOGON_INTERACTIVE = 2;
private const string m_domain = "PLACE YOUR ACTIVE DIRECTORY DOMAIN NAME HERE";
private const string m_sUser = "PLACE YOUR ADMINISTRATOR ACCOUNT'S USERNAME HERE";
private const string m_sPassword = "PLACE YOUR m_sUser PASSWORD HERE";
private static string m_lastUser = null;
private static DirectoryEntry m_rootDir;
private WindowsImpersonationContext m_impersonatedUser;
public enum SECURITY_IMPERSONATION_LEVEL {
  SecurityAnonymous = 0,
  SecurityIdentification = 1,
  SecurityImpersonation = 2,
  SecurityDelegation = 3
}
[DllImport("advapi32.dll", SetLastError = true)] // obtains user token
private static extern bool LogonUser(string pszUsername, string pszDomain, string pszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)] // closes open handes returned by LogonUser
private extern static bool CloseHandle(IntPtr handle);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] // creates duplicate token handle
private extern static bool DuplicateToken(IntPtr ExistingTokenHandle, int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle);

所有这些都用于我的课程中,模仿,这会使任何Windows帐户冒充 m_sUser

private void Impersonate() {
  IntPtr pExistingTokenHandle = IntPtr.Zero;
  IntPtr pDuplicateTokenHandle = IntPtr.Zero;
  m_lastUser = Environment.UserName;
  bool bImpersonated = LogonUser(m_sUser, m_domain, m_sPassword, LOGON_LOGON_INTERACTIVE, LOGON_PROVIDER_DEFAULT, ref pExistingTokenHandle);
  if (bImpersonated) {
    try {
      bool bRetVal = DuplicateToken(pExistingTokenHandle, (int)SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, ref pDuplicateTokenHandle);
      if (bRetVal) { // create new identity using new primary token
        using (var newId = new WindowsIdentity(pDuplicateTokenHandle)) {
          m_impersonatedUser = newId.Impersonate();
          m_rootDir = new DirectoryEntry(m_ldapPath);
        }
      } else { // did DuplicateToken fail?
        int nErrorCode = Marshal.GetLastWin32Error();
        string sResult = "DuplicateToken() failed with error code: " + nErrorCode + GSTR.CRLF;
        MessageBox.Show(sResult, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
      }
    } catch (Exception err) {
      MessageBox.Show(err.Message, "ADWrapper Error");
    } finally {
      m_working = false;
      if (!pDuplicateTokenHandle.Equals(IntPtr.Zero)) {
        CloseHandle(pDuplicateTokenHandle);
        pDuplicateTokenHandle = IntPtr.Zero;
      }
      if (!pExistingTokenHandle.Equals(IntPtr.Zero)) {
        CloseHandle(pExistingTokenHandle); // close existing handle
        pExistingTokenHandle = IntPtr.Zero;
      }
    }
  } else {
    int nErrorCode = Marshal.GetLastWin32Error();
    string sResult = "LogonUser() failed with error code: " + nErrorCode + GSTR.CRLF;
    MessageBox.Show(sResult, "Login Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
  }
}

当我第一次运行时,它在.NET Framework 2.0上运行,但在我离开之前它已升级到.NET 4.0。

我使用的是静态帐户,该帐户在我们的网络中设置为管理员,但您可能会看到如何修改此帐户以使用您的PIN验证具有某个用户名的用户。

不要忘记调用下面的Dispose()方法恢复为默认用户。如果包含此代码的类实现 IDisposable ,那么如果您忘记了GC,则很有可能被GC调用:

public void Revert() {
  if (m_impersonatedUser != null) {
    m_impersonatedUser.Undo();
    m_impersonatedUser = null;
  }
  if (m_rootDir != null) {
    m_rootDir.Close();
    Global.Dispose(m_rootDir);
    m_rootDir = null;
  }
}

public void Dispose() {
  Revert();
}

同样,我不再在该公司工作,因此我无法为您测试特定项目或告诉您特定场景返回的值类型。

我希望这会有所帮助。祝你好运!