Question

How do I create a second context pointing to another sitecollection (still same domain) by using the logged in user's credentials in SharePointOnline with CSOM C#? I don't want to login a second time.

This is how far I've got so far. But "currUser"'s Credentials is null.

var uri = new Uri(adress to my subsite)
var ctx2 = new ClientContext(uri);
var currUser = ctx.Web.CurrentUser;

ctx.Load(currUser );
ctx.ExecuteQuery();
ctx.Web.EnsureUser(currUser.LoginName);

ctx2.Credentials = currUser.Context.Credentials;
Était-ce utile?

La solution

You can either add PnP-Sites-Core via nuget as dependency and use extension method Clone:

var newctx = clientContext.Clone("https://new url");

or just add below method in your code base (I grabbed it from here):

/// <summary>
/// Clones a ClientContext object while "taking over" the security context of the existing ClientContext instance
/// </summary>
/// <param name="clientContext">ClientContext to be cloned</param>
/// <param name="siteUrl">Site URL to be used for cloned ClientContext</param>
/// <param name="accessTokens">Dictionary of access tokens for sites URLs</param>
/// <returns>A ClientContext object created for the passed site URL</returns>
public static ClientContext Clone(this ClientRuntimeContext clientContext, Uri siteUrl, Dictionary<String, String> accessTokens = null)
{
    if (siteUrl == null)
    {
        throw new ArgumentException(CoreResources.ClientContextExtensions_Clone_Url_of_the_site_is_required_, nameof(siteUrl));
    }

    ClientContext clonedClientContext = new ClientContext(siteUrl);
    clonedClientContext.AuthenticationMode = clientContext.AuthenticationMode;
    clonedClientContext.ClientTag = clientContext.ClientTag;

    // In case of using networkcredentials in on premises or SharePointOnlineCredentials in Office 365
    if (clientContext.Credentials != null)
    {
        clonedClientContext.Credentials = clientContext.Credentials;
    }
    else
    {
        //Take over the form digest handling setting
        clonedClientContext.FormDigestHandlingEnabled = (clientContext as ClientContext).FormDigestHandlingEnabled;

        var originalUri = new Uri(clientContext.Url);
        // If the cloned host is not the same as the original one
        // and if there is a custom Access Token for it in the input arguments
        if (originalUri.Host != siteUrl.Host &&
            accessTokens != null && accessTokens.Count > 0 &&
            accessTokens.ContainsKey(siteUrl.Authority))
        { 
            // Let's apply that specific Access Token
            clonedClientContext.ExecutingWebRequest += (sender, args) =>
            {
                args.WebRequestExecutor.RequestHeaders["Authorization"] = "Bearer " + accessTokens[siteUrl.Authority];
            };
        }
        else
        {
            // In case of app only or SAML
            clonedClientContext.ExecutingWebRequest += delegate (object oSender, WebRequestEventArgs webRequestEventArgs)
            {
                // Call the ExecutingWebRequest delegate method from the original ClientContext object, but pass along the webRequestEventArgs of 
                // the new delegate method
                MethodInfo methodInfo = clientContext.GetType().GetMethod("OnExecutingWebRequest", BindingFlags.Instance | BindingFlags.NonPublic);
                object[] parametersArray = new object[] { webRequestEventArgs };
                methodInfo.Invoke(clientContext, parametersArray);
            };
        }
    }

    return clonedClientContext;
}

Autres conseils

If the subweb is under the same site collection you can use the same context to get it.

Here's the example:

Site site = ctx.Site;
ctx.Load(site);
ctx.ExecuteQuery();

var p      = ResourcePath.FromDecodedUrl("/relative/path/to/subweb");
var subweb = site.OpenWebUsingPath(p);
ctx.ExecuteQuery();

ctx.Load(subweb, w => w.Url);
ctx.ExecuteQuery();
//here you have the subweb object pointing to the Web

EDIT: In the case of different site collection, you should be able to do something like this:

var siteUrl      = "https://anothersitecollectionurl";
var ctx2         = new ClientContext(siteUrl);
ctx2.Credentials = ctx.Credentials;

This works in the windows application, where the first context object (ctx) has been logged in by explicitly providing the username/password combination.

Licencié sous: CC-BY-SA avec attribution
Non affilié à sharepoint.stackexchange
scroll top