C# 我能';t获取页面以从Cookie加载用户角色

C# 我能';t获取页面以从Cookie加载用户角色,c#,forms-authentication,saml,cas,user-roles,C#,Forms Authentication,Saml,Cas,User Roles,我在iis7上建立了一个经过广告认证的网站,并将其迁移到IIS8.5。在此过程中,我尝试切换到表单身份验证。并非站点上的每个页面都是aspx页面-其中有静态内容和文件,因为它是intranet站点-但基本表单身份验证已经起作用,因为我将应用程序池设置为集成模式,并将web.config设置为使用表单身份验证。我很高兴,如果您尝试加载pdf文件,它将确保您首先登录到cas服务器 我的问题是角色-我在登录页面中设置了cookie,使其包含角色(我从CAS属性中提取),当我在该页面上设置User.Is

我在iis7上建立了一个经过广告认证的网站,并将其迁移到IIS8.5。在此过程中,我尝试切换到表单身份验证。并非站点上的每个页面都是aspx页面-其中有静态内容和文件,因为它是intranet站点-但基本表单身份验证已经起作用,因为我将应用程序池设置为集成模式,并将web.config设置为使用表单身份验证。我很高兴,如果您尝试加载pdf文件,它将确保您首先登录到cas服务器

我的问题是角色-我在登录页面中设置了cookie,使其包含角色(我从CAS属性中提取),当我在该页面上设置User.IsInRole()时,该页面会显示是的,此人拥有该角色。但是,如果我移动到一个新页面,无论是否为aspx,此人仍然经过身份验证,但不具有该角色。我试图避免使用角色管理器,因为我不想与提供者打交道(cas服务器正在处理身份验证部分),但如果必须,我将使用角色管理器。到目前为止我运气不好。我相信这些角色不是从cookies加载的,因为我将相同的(User.IsInRole(“staff”)?“True”:“False”;行,但在登录页上返回true,在主页上返回false

我将附加我的web配置和登录页面代码的相关部分

Web配置(仅公告文件夹使用atm角色):


登录页面代码背后的相关部分(重定向被注释掉,以便我可以看到他们的角色):

//第二次(从CAS返回)有一个票证=要验证
//CAS 3没有通过/serviceValidate列出属性,因此让我们构建一个SAML请求并使用它。
字符串SAMLstr=“”+
“”+tkt+“”+
"";
字符串validateurl=CASHOST+“samlValidate?TARGET=“+service+”&ticket=“+tkt;
//设置一个xml文档来捕获SAML响应,然后对其进行解析。
XmlDocument xmlDoc=新的XmlDocument();
LoadXml(新的WebClient().UploadString(validateurl,SAMLstr));
//响应使用多个名称空间,哇!
var nsmgr=新的XmlNamespaceManager(xmlDoc.NameTable);
nsmgr.AddNamespace(“s”http://schemas.xmlsoap.org/soap/envelope/");
nsmgr.AddNamespace(“nsR”、“urn:oasis:names:tc:SAML:1.0:protocol”);
AddNamespace(“nsA”,“urn:oasis:names:tc:SAML:1.0:assertion”);
//让我们看看他们是否成功授权:
if(xmlDoc.SelectSingleNode(“/s:Envelope/s:Body/nsR:Response/nsR:Status/nsR:StatusCode”,nsmgr)。属性[“Value”]。值==(“samlp:Success”)){
//他们成功地进行了身份验证;填充了他们的id和角色。
字符串netid=xmlDoc.SelectSingleNode(“/s:Envelope/s:Body/nsR:Response/nsA:Assertion/nsA:AuthenticationStatement/nsA:Subject/nsA:NameIdentifier”,nsmgr);
//抓取“memberOf”属性-它包含每个组可分辨名称的子节点。
XmlNode memberOf=xmlDoc.SelectSingleNode(“/s:Envelope/s:Body/nsR:Response/nsA:Assertion/nsA:AttributeStatement/nsA:Attribute[@AttributeName='memberOf']”,nsmgr);
//我不想重复,所以我只需要抓取所有文本,并用正则表达式将其拆分,以拆分OU和DC。
string[]groups=Regex.Split(memberOf.InnerText.ToLower().Substring(3),“cn=(*?),ou=”;
HttpContext.Current.User=新的GenericPrincipal(新的GenericEntity(netid),新字符串[]{“staff”,“union”,“UTech”});
//将组名称拼接在一起,但删除OU(每隔一个条目)
字符串角色=组[1];

对于(intx=3;x我讨厌回答我自己的问题,但经过一周的搜索和阅读教程,我终于找到了答案

上述问题中的cookies和表单身份验证没有问题;没有加载角色的原因是我的global.asax中没有PostAuthenticateRequest(事实上根本没有global.asax)。是最有帮助的,不是来自已接受的答案,而是来自P.Hoxha的一个附加项。P.Hoxha投了0票,但我投了更高的票。Microsoft教程也有助于更正我投了更高票的回复中不起作用的内容

通过捕获PostAuthenticateRequest并运行以下代码加载角色,添加global.asax解决了此问题:

<%@ Application Language="C#" %>
<%@ Import Namespace="System.Security.Principal" %>
<%@ Import Namespace="System.Threading" %>

<script runat="server">
void Application_OnPostAuthenticateRequest(object sender, EventArgs e) {
  HttpCookie authCookie = Context.Request.Cookies[FormsAuthentication.FormsCookieName];
  if (authCookie == null || authCookie.Value == "") return;
  FormsAuthenticationTicket authTicket;
  try {
    authTicket = FormsAuthentication.Decrypt(authCookie.Value);
  } catch {
    return;
  }

  // retrieve roles from UserData
  string[] roles = authTicket.UserData.Split('|');

  if (Context.User != null) Context.User = new GenericPrincipal(Context.User.Identity, roles);
}
</script>

无效应用程序\u OnPostAuthenticateRequest(对象发送方,事件参数e){
HttpCookie authCookie=Context.Request.Cookies[FormsAuthentication.FormsCookieName];
if(authCookie==null | | authCookie.Value==“”)返回;
FormsAuthenticationTicket身份证;
试一试{
authTicket=FormsAuthentication.Decrypt(authCookie.Value);
}抓住{
返回;
}
//从UserData检索角色
string[]roles=authTicket.UserData.Split(“|”);
如果(Context.User!=null)Context.User=new GenericPrincipal(Context.User.Identity,roles);
}
  // Second time (back from CAS) there is a ticket= to validate
  // CAS 3 doesn't list attributes through /serviceValidate, so lets build a SAML request and use that instead.
  string SAMLstr = "<?xml version='1.0'?><SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">" +
    "<SOAP-ENV:Header/><SOAP-ENV:Body><samlp:Request xmlns:samlp=\"urn:oasis:names:tc:SAML:1.0:protocol\" " +
    "MajorVersion=\"1\" MinorVersion=\"1\" RequestID=\"_" + Request.ServerVariables["REMOTE_HOST"] + "." + DateTime.Now.Ticks + "\"" +
    "IssueInstant=\"" + DateTime.Now + "\"><samlp:AssertionArtifact>" + tkt + "</samlp:AssertionArtifact>" +
    "</samlp:Request></SOAP-ENV:Body></SOAP-ENV:Envelope>";
  string validateurl = CASHOST + "samlValidate?TARGET=" + service + "&ticket=" + tkt;
  // Set up an xml document to catch the SAML responce and then parse it.
  XmlDocument xmlDoc = new XmlDocument();
  xmlDoc.LoadXml(new WebClient().UploadString(validateurl, SAMLstr));
  // The response uses multiple namespaces, whee!
  var nsmgr = new XmlNamespaceManager(xmlDoc.NameTable);
  nsmgr.AddNamespace("s", "http://schemas.xmlsoap.org/soap/envelope/");
  nsmgr.AddNamespace("nsR", "urn:oasis:names:tc:SAML:1.0:protocol");
  nsmgr.AddNamespace("nsA", "urn:oasis:names:tc:SAML:1.0:assertion");
  // Let's see if they authed successfully:
  if (xmlDoc.SelectSingleNode("/s:Envelope/s:Body/nsR:Response/nsR:Status/nsR:StatusCode", nsmgr).Attributes["Value"].Value == ("samlp:Success")) {
    // They authenticated successfully; populate their id and roles.
    string netid = xmlDoc.SelectSingleNode("/s:Envelope/s:Body/nsR:Response/nsA:Assertion/nsA:AuthenticationStatement/nsA:Subject/nsA:NameIdentifier", nsmgr).InnerText; 
    // Grab the "memberOf" attriubute - it contains a child node for each group distinguished name.
    XmlNode memberOf = xmlDoc.SelectSingleNode("/s:Envelope/s:Body/nsR:Response/nsA:Assertion/nsA:AttributeStatement/nsA:Attribute[@AttributeName='memberOf']", nsmgr);
    // I don't want to iterate through that, so I'll just grab all the text and split it with a regex to split up the OUs and DCs.
    string[] groups = Regex.Split(memberOf.InnerText.ToLower().Substring(3), "cn=(.*?),ou=");
    HttpContext.Current.User = new GenericPrincipal(new GenericIdentity(netid),new string[] {"staff", "union", "UTech"});

    // Splicing together the groups names but droping the OUs (every other entry)
    string roles=groups[1];
    for (int x=3;x<groups.Length;x+=2) roles+="|"+groups[x];
    // Let's bake cookies with the netid, roles, and persistence.  1: Make the ticket.
    FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, netid, DateTime.Now, DateTime.Now.AddMinutes(2880), isPersistent, roles, FormsAuthentication.FormsCookiePath);
    // 2. Encrypt the ticket.
    string hash = FormsAuthentication.Encrypt(ticket);
    // 3. Turn the encrypted ticket into a cookie!
    HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, hash);
    // 4. Set expiration on the cookie to match the ticket.
    if (ticket.IsPersistent) cookie.Expires = ticket.Expiration;
    // 5. Put the cookie in the jar.
    Response.Cookies.Add(cookie);
    // We're done!  Send them home.
    // [TEMP, next 3 lines are debug] Response.Redirect(service + Session["backto"], true);
    Label1.Text = "Welcome, "+netid+"!";
    Label2.Text = roles;
    Label3.Text = (User.IsInRole("staff"))?"True":"False";
<%@ Application Language="C#" %>
<%@ Import Namespace="System.Security.Principal" %>
<%@ Import Namespace="System.Threading" %>

<script runat="server">
void Application_OnPostAuthenticateRequest(object sender, EventArgs e) {
  HttpCookie authCookie = Context.Request.Cookies[FormsAuthentication.FormsCookieName];
  if (authCookie == null || authCookie.Value == "") return;
  FormsAuthenticationTicket authTicket;
  try {
    authTicket = FormsAuthentication.Decrypt(authCookie.Value);
  } catch {
    return;
  }

  // retrieve roles from UserData
  string[] roles = authTicket.UserData.Split('|');

  if (Context.User != null) Context.User = new GenericPrincipal(Context.User.Identity, roles);
}
</script>