.net 应用无法识别授权用户
.net app is not recognizing authorized user
我有一个包含 4 个项目的 C#.net 3.5 WAP 解决方案。 Web 应用程序仅允许访问经理和 HR。授权由 AD 角色在 web.config 中授予。问题是所有经理都可以访问应用程序的 Default 和 Page2,但一位经理除外,他也应该能够访问 Page2 但不能(我称他为 specialmanager)(但可以访问 Default)。当尝试通过 URL 使用查询字符串或通过 select 命令 link 从默认页面上的 gridview 行访问 Page2 时,specialmanager 被重定向到自定义访问被拒绝页面。
Web.config:
<authorization>
<allow roles="abc\hr, abc\managers, abc\it, abc\software tester"/>
<allow users="abc\specialmanager"/>
<!--<deny users="*"/>-->
<!--<allow users="*"/>--><!--default-->
</authorization>
<authentication mode="Windows"/>
<identity impersonate="true"/>
<customErrors mode="Off" defaultRedirect="~/Warning/AccessDenied.aspx">
<error statusCode="401" redirect="~/Warning/AccessDenied.aspx" />
</customErrors>
我尝试在执行重定向的方法中记录事件的历史记录,但是当我将错误记录放在 try catch 之外时,随之而来的是 HTTP 401.2 错误。我已经检查了这个用户的 SQL 安全性,它是正确的——它与其他有权访问的用户一样。我已经验证此用户是被授予访问权限的 AD 组的成员。除了角色之外,我什至还允许这个特定用户在 Web 配置中作为用户进行额外访问,并且相同的重定向到自定义访问被拒绝的页面结果。
我在我的本地调试机器上模拟了这个用户,并且在我的机器上一切正常,但在他的机器上从服务器访问时却不行,所以我无法真正复制他正在发生的事情。
我在每个页面的 UI 上都标识了用户名,并且正确标识了他。我不确定如何调试它以找出应用程序认为他未被授权的原因。如果他以这种方式访问它,他的用户名必须与默认网格行中列出的 3 位审阅者中的 1 位相匹配,确实如此。
我只发布了可能相关的代码。我需要有关如何调试它的想法的帮助 - 有什么想法吗?
获取用户名的代码:
//returns username portion of AD domain\username
public String GetUserName()
{
string curUser = Environment.UserName; //returns the logged-in account-name
//// impersonate a specific user during testing & development+
//if (curUser == "user1" || curUser == "user2")
//{
// curUser = "specialuser"; //local dev. Test as user specified here.
//}
//else
//{
// return curUser;
//}
return curUser;
}
//check current user's membership in AD groups that are allowed to view form
//ref:
public List<Boolean> CheckGroupMembership()
{
List<bool> blnIsMember = new List<bool>();
// set up domain context
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "abc");
// find a user
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, GetUserName());
for (int i = 0; i <= 3; i++)
{
// find the group in question
GroupPrincipal group = GroupPrincipal.FindByIdentity(ctx, _groupName[i]);
if (user != null)
{
// check if user is member of that group
if (user.IsMemberOf(group))
{
_IsMember[i] = true;
blnIsMember.Add(_IsMember[i]);//add array to list
}
else
{
_IsMember[i] = false;
blnIsMember.Add(_IsMember[i]);
}
}
}
return blnIsMember;
}
第2页,Page_Load()
protected void Page_Load(object sender, EventArgs e)
{
lblProgressStatus.Text = "";
//Handle security depending on user's point of entry; 1) from app's default page or 2)Page2, URL/clicking on link in email notificiation
//call I_CurrentUser interface
I_CurrentUser user = new ReviewData();
//get current username
strCurrentUser = user.GetUserName();
HttpContext.Current.Session["UserName"] = strCurrentUser;
//check current user's membership against AD groups needed to gain access
_IsMember = user.CheckGroupMembership();
//pass list to array
IsMember = _IsMember.ToArray(); //0=Admin, 1=Manager, 2=Developer, 3=Software Tester
//Hide Admin link if current user is NOT a member of admin[0], developer[2] or software tester[3] group
if (IsMember[0] == true || IsMember[2] == true || IsMember[3] == true)
{
//Link to Admin page
LinkButton3.Visible = true;
}
else
{
//Link to Admin page
LinkButton3.Visible = false;
}
//prepare to log any error messages
DataLib.ErrorLog oErrorLog = new DataLib.ErrorLog();
if (!IsPostBack)
{
try
{
if (!string.IsNullOrEmpty(Request.QueryString["ID"]))
{
string id = Request.QueryString["ID"];
intID = Convert.ToInt16(id);
string strID = intID.ToString();
ViewState["ID"] = strID;
Session["ID"] = strID;
AuthorizeCurrentUserSelection(intID, strCurrentUser);
/* If DocID is not in querystring, the user has accessed form via URL. Determine if DocID exists:
* if it doesn't, Insert prelim record, if it does, update formname.
* Else DocID is in querystring.*/
if (string.IsNullOrEmpty(Request.QueryString["DocID"]))
{
DataLib.EPRConn oGetID = new DataLib.EPRConn();
intDocID = oGetID.SelectDocID(intID); //if docid does not exist it will return integer 0
string strDocID = intDocID.ToString();
ViewState["SelectedDocID"] = strDocID;
Session["SelectedDocID"] = strDocID;
//Insert DocID when it's null or empty, or "0"
if (string.IsNullOrEmpty(strDocID) || strDocID == "0")
{
/*4/24/17 IMPORTANT: InsertDocID() executes an initial INSERT DocID into tbl1 and tbl2,
this allows Ratings to be UPDATED rather than INSERTED when radio buttons are
subsequently ticked and establishes DocID and FormName prior to first submit/save.*/
DataLib.EPRConn oInsertID = new DataLib.EPRConn();
oInsertID.InsertDocID(Convert.ToInt32(ViewState["ID"]), intDocID);
}
else //Update FormName if DocID exists.
{
FillCommentTextBoxes(strID);
FillMeritIncreaseTextBox();
//Update tbl1.FormName and tbl2 where FormName IS NULL (to assign names to older forms created prior to this app's launch
DataLib.EPRConn oFN = new DataLib.EPRConn();
oFN.UpdateFormName(intID);
}
}
else //DocID exists in querystring.
{
string dID = Request.QueryString["DocID"];
intDocID = Convert.ToInt16(dID);
string strDocID = intDocID.ToString();
ViewState["SelectedDocID"] = strDocID;
Session["SelectedDocID"] = strDocID;
FillCommentTextBoxes(strID);
FillMeritIncreaseTextBox();
//Update FormName in 2 tables where FormName IS NULL (to assign names to older forms created prior to this app's
DataLib.EPRConn oFN = new DataLib.EPRConn();
oFN.UpdateFormName(intID);
}
重定向到 Page2 的代码:
//pass form ID and viewing supervisor/current user
protected void AuthorizeCurrentUserSelection(int ID, string supUserName)
{
//Create a list of strings to hold up to 3 reviewers of selected employee
List<string> strLine = new List<string>();
//prepare to log any errors thrown
DataLib.ErrorLog oErrorLog = new DatLib.ErrorLog();
try
{
//return all rows from tbl
DataLib.EPRConn oAuth = new DataLib.EPRConn();
strLine = oAuth.SelectSupervisorUserName(eID, supUserName);
string[] arr = strLine.ToArray();
string strLevel1 = arr[0];
string strLevel2 = arr[1];
string strLevel3 = arr[2];
//0=Admin, 1=Manager, 2=Developer, 3=Software Tester.
if (IsMember[0] == true || IsMember[2] == true || IsMember[3] == true {
BindRepeater();
}
//if current user is a manager and named in level1, 2 or 3, load grid
else if ((strLevel1 == strCurrentUser && IsMember[1] == true) ||
(strLevel2 == strCurrentUser && IsMember[1] == true) ||
(strLevel3 == strCurrentUser && IsMember[1] == true))
{
//Example of error log that throws HTTP 401 error when uncommented
//oErrorLog.WriteErrorLog("(strCurrentUser=" + strCurrentUser + ") History Log: Line398-401_AuthorizeCurrentUserSelection(" + eID + ", supUserName=" + supUserName + "). Level1=" + strLevel1 + ", Level2=" + strLevel2 + ", Level3=" + strLevel3 + ", IsMember[1]=true ");
//hide Lock/Unlock buttons
Panel1.Visible = false;
//show grid
BindRepeater();
}
else
{
//redirect
Response.Redirect("~/Warning/AccessDenied.aspx");
}//end if/else
}//end try
catch (SqlException ex)
{
oErrorLog.WriteErrorLog("(" + strCurrentUser + ")SqlException in ReviewForm_AuthorizeCurrentUserSelection(): " + ex.ToString());
} //end catch
}
我和我的 NA 解决了这个问题。用于检索当前用户的代码是 System.Environment.UserName
,它在 AD 属性中检索 2000 年之前的显示名称,例如显示为“SManager
”而不是“smanager
”。为允许访问应用程序的第 2 页而进行的比较需要小写,因此在这种情况下,SPmanager
与要比较的 3 位评论者列表中的 smanager
不匹配。
解决方案是更改 AD 中 2000 年前的用户名,其中大写首字母曾经被用于所有小写,现在在较新版本的 AD 中会自动完成。
我有点不满意 MSDN 没有准确指定它在哪里检索用户名 属性。
我有一个包含 4 个项目的 C#.net 3.5 WAP 解决方案。 Web 应用程序仅允许访问经理和 HR。授权由 AD 角色在 web.config 中授予。问题是所有经理都可以访问应用程序的 Default 和 Page2,但一位经理除外,他也应该能够访问 Page2 但不能(我称他为 specialmanager)(但可以访问 Default)。当尝试通过 URL 使用查询字符串或通过 select 命令 link 从默认页面上的 gridview 行访问 Page2 时,specialmanager 被重定向到自定义访问被拒绝页面。
Web.config:
<authorization>
<allow roles="abc\hr, abc\managers, abc\it, abc\software tester"/>
<allow users="abc\specialmanager"/>
<!--<deny users="*"/>-->
<!--<allow users="*"/>--><!--default-->
</authorization>
<authentication mode="Windows"/>
<identity impersonate="true"/>
<customErrors mode="Off" defaultRedirect="~/Warning/AccessDenied.aspx">
<error statusCode="401" redirect="~/Warning/AccessDenied.aspx" />
</customErrors>
我尝试在执行重定向的方法中记录事件的历史记录,但是当我将错误记录放在 try catch 之外时,随之而来的是 HTTP 401.2 错误。我已经检查了这个用户的 SQL 安全性,它是正确的——它与其他有权访问的用户一样。我已经验证此用户是被授予访问权限的 AD 组的成员。除了角色之外,我什至还允许这个特定用户在 Web 配置中作为用户进行额外访问,并且相同的重定向到自定义访问被拒绝的页面结果。 我在我的本地调试机器上模拟了这个用户,并且在我的机器上一切正常,但在他的机器上从服务器访问时却不行,所以我无法真正复制他正在发生的事情。 我在每个页面的 UI 上都标识了用户名,并且正确标识了他。我不确定如何调试它以找出应用程序认为他未被授权的原因。如果他以这种方式访问它,他的用户名必须与默认网格行中列出的 3 位审阅者中的 1 位相匹配,确实如此。
我只发布了可能相关的代码。我需要有关如何调试它的想法的帮助 - 有什么想法吗?
获取用户名的代码:
//returns username portion of AD domain\username
public String GetUserName()
{
string curUser = Environment.UserName; //returns the logged-in account-name
//// impersonate a specific user during testing & development+
//if (curUser == "user1" || curUser == "user2")
//{
// curUser = "specialuser"; //local dev. Test as user specified here.
//}
//else
//{
// return curUser;
//}
return curUser;
}
//check current user's membership in AD groups that are allowed to view form
//ref:
public List<Boolean> CheckGroupMembership()
{
List<bool> blnIsMember = new List<bool>();
// set up domain context
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "abc");
// find a user
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, GetUserName());
for (int i = 0; i <= 3; i++)
{
// find the group in question
GroupPrincipal group = GroupPrincipal.FindByIdentity(ctx, _groupName[i]);
if (user != null)
{
// check if user is member of that group
if (user.IsMemberOf(group))
{
_IsMember[i] = true;
blnIsMember.Add(_IsMember[i]);//add array to list
}
else
{
_IsMember[i] = false;
blnIsMember.Add(_IsMember[i]);
}
}
}
return blnIsMember;
}
第2页,Page_Load()
protected void Page_Load(object sender, EventArgs e)
{
lblProgressStatus.Text = "";
//Handle security depending on user's point of entry; 1) from app's default page or 2)Page2, URL/clicking on link in email notificiation
//call I_CurrentUser interface
I_CurrentUser user = new ReviewData();
//get current username
strCurrentUser = user.GetUserName();
HttpContext.Current.Session["UserName"] = strCurrentUser;
//check current user's membership against AD groups needed to gain access
_IsMember = user.CheckGroupMembership();
//pass list to array
IsMember = _IsMember.ToArray(); //0=Admin, 1=Manager, 2=Developer, 3=Software Tester
//Hide Admin link if current user is NOT a member of admin[0], developer[2] or software tester[3] group
if (IsMember[0] == true || IsMember[2] == true || IsMember[3] == true)
{
//Link to Admin page
LinkButton3.Visible = true;
}
else
{
//Link to Admin page
LinkButton3.Visible = false;
}
//prepare to log any error messages
DataLib.ErrorLog oErrorLog = new DataLib.ErrorLog();
if (!IsPostBack)
{
try
{
if (!string.IsNullOrEmpty(Request.QueryString["ID"]))
{
string id = Request.QueryString["ID"];
intID = Convert.ToInt16(id);
string strID = intID.ToString();
ViewState["ID"] = strID;
Session["ID"] = strID;
AuthorizeCurrentUserSelection(intID, strCurrentUser);
/* If DocID is not in querystring, the user has accessed form via URL. Determine if DocID exists:
* if it doesn't, Insert prelim record, if it does, update formname.
* Else DocID is in querystring.*/
if (string.IsNullOrEmpty(Request.QueryString["DocID"]))
{
DataLib.EPRConn oGetID = new DataLib.EPRConn();
intDocID = oGetID.SelectDocID(intID); //if docid does not exist it will return integer 0
string strDocID = intDocID.ToString();
ViewState["SelectedDocID"] = strDocID;
Session["SelectedDocID"] = strDocID;
//Insert DocID when it's null or empty, or "0"
if (string.IsNullOrEmpty(strDocID) || strDocID == "0")
{
/*4/24/17 IMPORTANT: InsertDocID() executes an initial INSERT DocID into tbl1 and tbl2,
this allows Ratings to be UPDATED rather than INSERTED when radio buttons are
subsequently ticked and establishes DocID and FormName prior to first submit/save.*/
DataLib.EPRConn oInsertID = new DataLib.EPRConn();
oInsertID.InsertDocID(Convert.ToInt32(ViewState["ID"]), intDocID);
}
else //Update FormName if DocID exists.
{
FillCommentTextBoxes(strID);
FillMeritIncreaseTextBox();
//Update tbl1.FormName and tbl2 where FormName IS NULL (to assign names to older forms created prior to this app's launch
DataLib.EPRConn oFN = new DataLib.EPRConn();
oFN.UpdateFormName(intID);
}
}
else //DocID exists in querystring.
{
string dID = Request.QueryString["DocID"];
intDocID = Convert.ToInt16(dID);
string strDocID = intDocID.ToString();
ViewState["SelectedDocID"] = strDocID;
Session["SelectedDocID"] = strDocID;
FillCommentTextBoxes(strID);
FillMeritIncreaseTextBox();
//Update FormName in 2 tables where FormName IS NULL (to assign names to older forms created prior to this app's
DataLib.EPRConn oFN = new DataLib.EPRConn();
oFN.UpdateFormName(intID);
}
重定向到 Page2 的代码:
//pass form ID and viewing supervisor/current user
protected void AuthorizeCurrentUserSelection(int ID, string supUserName)
{
//Create a list of strings to hold up to 3 reviewers of selected employee
List<string> strLine = new List<string>();
//prepare to log any errors thrown
DataLib.ErrorLog oErrorLog = new DatLib.ErrorLog();
try
{
//return all rows from tbl
DataLib.EPRConn oAuth = new DataLib.EPRConn();
strLine = oAuth.SelectSupervisorUserName(eID, supUserName);
string[] arr = strLine.ToArray();
string strLevel1 = arr[0];
string strLevel2 = arr[1];
string strLevel3 = arr[2];
//0=Admin, 1=Manager, 2=Developer, 3=Software Tester.
if (IsMember[0] == true || IsMember[2] == true || IsMember[3] == true {
BindRepeater();
}
//if current user is a manager and named in level1, 2 or 3, load grid
else if ((strLevel1 == strCurrentUser && IsMember[1] == true) ||
(strLevel2 == strCurrentUser && IsMember[1] == true) ||
(strLevel3 == strCurrentUser && IsMember[1] == true))
{
//Example of error log that throws HTTP 401 error when uncommented
//oErrorLog.WriteErrorLog("(strCurrentUser=" + strCurrentUser + ") History Log: Line398-401_AuthorizeCurrentUserSelection(" + eID + ", supUserName=" + supUserName + "). Level1=" + strLevel1 + ", Level2=" + strLevel2 + ", Level3=" + strLevel3 + ", IsMember[1]=true ");
//hide Lock/Unlock buttons
Panel1.Visible = false;
//show grid
BindRepeater();
}
else
{
//redirect
Response.Redirect("~/Warning/AccessDenied.aspx");
}//end if/else
}//end try
catch (SqlException ex)
{
oErrorLog.WriteErrorLog("(" + strCurrentUser + ")SqlException in ReviewForm_AuthorizeCurrentUserSelection(): " + ex.ToString());
} //end catch
}
我和我的 NA 解决了这个问题。用于检索当前用户的代码是 System.Environment.UserName
,它在 AD 属性中检索 2000 年之前的显示名称,例如显示为“SManager
”而不是“smanager
”。为允许访问应用程序的第 2 页而进行的比较需要小写,因此在这种情况下,SPmanager
与要比较的 3 位评论者列表中的 smanager
不匹配。
解决方案是更改 AD 中 2000 年前的用户名,其中大写首字母曾经被用于所有小写,现在在较新版本的 AD 中会自动完成。
我有点不满意 MSDN 没有准确指定它在哪里检索用户名 属性。