c# - 如何通过 WebRequest 调用 MVC 操作并通过 Active Directory 验证请求?

标签 c# asp.net-mvc-3 web-services authentication active-directory

我知道这个标题很拗口。我已经把大部分事情都准备好了。我只需要确认我是否可以做我正在尝试的事情。

我正在使用 ASP.NET MVC 3。我有一个应用程序,它具有我像 Web 服务一样使用的 Controller 。 Controller 上有一个方法,它返回一个字符串,即 json。此方法根据事件目录对用户进行身份验证。

对上面的应用程序执行WebRequest也是一个MVC应用程序。此应用程序(为了在没有特定用户名和密码的情况下查询 AD)在 web.config 中使用模拟。应用程序冒充有权限查询AD的账户;但是,我验证的内容是页面上用户的信息(例如他们所在的组)。

简而言之(我并不完全理解这部分),模拟是严格的,以便 ASP.NET 可以查询 Active Directory。当我查询事件目录以获取其信息时,加载页面的用户仍然被视为他们自己。

AD 代码如下所示(此代码有效):

   public static ADUserInfo GetUserInfo(IPrincipal User)
    {
        StringBuilder userAdInfo = new StringBuilder();
        ADUserInfo userInfo = new ADUserInfo();
        String domain = ConfigurationManager.AppSettings["ADdomain"];

        try
        {
            using (var context = new PrincipalContext(ContextType.Domain, domain))
            {
                if (User == null)
                    userAdInfo.AppendLine("User is null.");
                else if (User.Identity == null)
                    userAdInfo.AppendLine(" User is not null. User.Identitiy is.");
                else
                    userAdInfo.AppendLine(" Neither User nor User.Identity is null. " +
                        User.Identity.Name);

                using (var user = UserPrincipal.FindByIdentity(context, User.Identity.Name))
                {
                    userInfo.FullName = user.Name;
                    userInfo.Email = user.EmailAddress;
                    userInfo.AssociateId = user.EmployeeId;
                    userInfo.DomainName = User.Identity.Name;
                    userInfo.SamAccountName = user.SamAccountName;
                    userInfo.DistinguishedUserName = user.DistinguishedName;
               }
            }
        }
        catch (Exception e)
        {
            LogUtil.WriteException(e);
        }
        return userInfo;
    }

此应用程序的 IIS 站点不允许匿名访问。

使用AD信息的服务方法工作正常。问题似乎是通过 WebRequest 传递凭据以调用此方法并获取返回的 JSON。

我的调用该操作的 WebRequest 代码如下所示:

    public class WebRequestUtil
    {
        public static StreamReader GetWebRequestStream(
             string url,
             string contentType,
             bool useDefaultCredentials)
        {
            var request = WebRequest.Create(url);
            request.ContentType = contentType;
            request.ImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
            //request.UseDefaultCredentials = useDefaultCredentials;
            //ICredentials ic = new NetworkCredential();

            //request.Credentials = 
            var response = (HttpWebResponse)request.GetResponse();
            return new StreamReader(response.GetResponseStream());
        }
    }

我正在玩 ImpersonationLevel...还没有工作...

通过 WebRequest 调用的 MVC 3 操作类似于:

public class ProxyServiceController : Controller
    {

        public ProxyServiceController()
        {

        }

       public string CheckForProxy(string applicationName, string associateId)
        {
            RequestResultDetails requestDetails = new RequestResultDetails();
            string json = string.Empty;

            //This correctly gets the Active directory information for the user
            //and fills out a custom ADUserInfo object.
            **ADUserInfo adUserInfo = ADService.GetUserInfo(this.User);**

            try
            {

                if (!ADService.DoesUrlDataMatchAD(
                                adUserInfo,
                                associateId)
                    )
                {
                    throw new Exception(StaticText.UserDataMismatch);
                }

                resultList = //query db for data given the associateId

                if (resultList.ListIsNotNullOrEmpty())
                {
                    requestDetails.RelationshipExists = true;
                }
                else
                {
                    requestDetails.RelationshipExists = false;
                }

                requestDetails.Details = resultList;

            }
            catch (Exception e)
            {
                LogUtil.WriteException(e);
                requestDetails.ErrorProcessingRequest = true;
                requestDetails.ErrorDetails = ErrorProcessing.GetFullExceptionDetails(e);
            }

            json = JsonConvert.SerializeObject(requestDetails);

            LogUtil.Write("json: " + json);

            return json;

        }
}       

那么,如果我通过如下网址直接在浏览器中访问 MVC 3 Controller /操作,会发生什么:

http://:90/MyApp/Service.aspx/CheckForProxy/Reporting/555

我可以在页面上看到正确的 JSON。但是,如果我从同一服务器上的另一个应用程序对同一 URL 进行 WebRequest 调用,则 Active Directory 似乎无法进行轮询。这肯定是某种权限问题,但我不确定如何解决它,以便服务可以看到用户的 Active Directory 信息。

这里的问题是传递给服务的凭据是调用应用程序所模拟的帐户的凭据。我该如何更改才能让服务 mvc 应用程序看到执行 WebRequest 的用户(应用程序进行调用,但用户加载应用程序)而不是应用程序模拟的帐户?

我对处理此沟通的其他想法或方法持开放态度。

jmrnet 评论的解决方案

哇,这个评论说得很对。我不知道正在发挥什么样的网络魔法,但我将我的网络请求方法修改为:

  public static StreamReader GetWebRequestStream(
         string url,
         string contentType,
         bool useDefaultCredentials,
         IPrincipal user)
    {

        var impersonationContext = ((WindowsIdentity)user.Identity).Impersonate();            
        var request = WebRequest.Create(url);

        try
        {
            request.ContentType = contentType;
            request.AuthenticationLevel = System.Net.Security.AuthenticationLevel.MutualAuthRequested;
            request.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
            var response = (HttpWebResponse)request.GetResponse();
            return new StreamReader(response.GetResponseStream());
        }
        catch (Exception e)
        {
            impersonationContext.Undo();
            throw e;
        }

    }

这准确地传递了主要用户的身份。

最佳答案

两个想法:

1) 您可以在进行 WebRequest 调用之前尝试强制模拟。像这样:

var impersonationContext = ((WindowsIdentity)User.Identity).Impersonate();
//Make your WebRequest call here...
impersonationContext.Undo();

2) 您可以在 WebRequest 调用中传递用户,在服务端从 AD 获取用户身份,然后使用上述代码的变体来模拟他们。

这里是一个链接,详细讨论了上面使用的模拟代码: http://msdn.microsoft.com/en-us/library/w070t6ka.aspx

关于c# - 如何通过 WebRequest 调用 MVC 操作并通过 Active Directory 验证请求?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13771992/

相关文章:

c# - 在 C# 中执行基于存储过程的查询后,如何为 CommandText 重新使用 SqlCommand 对象?

javascript - 在 Angular 中将 JSON 格式字符串转换为真实对象

c# - 如何将 Group KEY 从 LINQ 转换为 int?

c# - 升级 XML 文件的序列化程序

c# - 用于比较 string[] 是否包含给定字符串的 lambda 表达式

c# - Application_Start 是否在 Web.config 文件转换之前执行?

asp.net-mvc-3 - 如何根据当前页面和/或主页向 Orchard CMS 中的布局包装器添加类

web-services - maven中基于wsdl文件生成wsdl文件和webservice客户端

java - 在 XFire 中解析 XML 会导致 CPU 高吗?

c# - 将字符串加密和解密为固定长度