当前位置: 首页 > 知识库问答 >
问题:

使用Java访问Azure中的Office 365(sharepoint REST api)

梁丘书
2023-03-14

我不熟悉Azure和sharepoint与Java的集成。

我正在尝试将Java与Sharepoint整合。Sharepoint-Office 365在Azure ADFS提供。我需要编写一个Java程序进行身份验证,然后使用Sharepoint提供的RESTful APIs访问文件。Azure正在使用WS-Federation身份验证过程。我一直在试图寻找帮助我使用WS-F认证的代码,然后访问这些文件。我找不到任何有用的材料。

基本身份验证不起作用,我也没有参与过WS-F身份验证。所以没有从哪里开始的线索。我还使用了Office-365-sdk来实现这一点,但无法实现,因为它使用的是客户端ID和其他与我的应用程序无关的属性。例如,不需要客户端ID,因为共享点已经可用。

我也得到了这个链接,但是缺少一些方法,它没有解释用于实现的库。请指导我实现这一点。

共有1个答案

赫连卓
2023-03-14

下面是您提到的文章中的一段代码:

package com.waveaccess.someproject.commons.service;

import com.waveaccess.someproject.commons.config.Const;
import com.waveaccess.someproject.commons.config.properties.SharePointProperties;
import com.waveaccess.someproject.commons.service.exceptions.SharePointAuthenticationException;
import com.waveaccess.someproject.commons.service.exceptions.SharePointSignInException;
import com.google.common.base.Joiner;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.xml.transform.StringSource;
import org.springframework.xml.xpath.XPathExpression;
import org.w3c.dom.Document;

import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * @author Maksim Kanev
 */
@Service
public class SharePointServiceCached {

    private static final Logger log = LoggerFactory.getLogger(SharePointServiceCached.class);

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private SharePointProperties sharePointProperties;

    @Autowired
    private XPathExpression xPathExpression;

    @Cacheable(Const.CACHE_NAME_TOKEN)
    public String receiveSecurityToken(Long executionDateTime) throws TransformerException, URISyntaxException {
        RequestEntity<String> requestEntity = new RequestEntity<>(buildSecurityTokenRequestEnvelope(), HttpMethod.POST, new URI(sharePointProperties.getEndpoint() + "/extSTS.srf"));
        ResponseEntity<String> responseEntity = restTemplate.exchange(requestEntity, String.class);

        DOMResult result = new DOMResult();
        Transformer transformer = TransformerFactory.newInstance().newTransformer();
        transformer.transform(new StringSource(responseEntity.getBody()), result);
        Document definitionDocument = (Document) result.getNode();

        String securityToken = xPathExpression.evaluateAsString(definitionDocument);
        if (StringUtils.isBlank(securityToken)) {
            throw new SharePointAuthenticationException("Unable to authenticate: empty token");
        }
        log.debug("Microsoft Online respond with Token: {}", securityToken);
        return securityToken;
    }

    private String buildSecurityTokenRequestEnvelope() {
        String envelopeTemplate = "<s:Envelope xmlns:s=\"http://www.w3.org/2003/05/soap-envelope\" xmlns:a=\"http://www.w3.org/2005/08/addressing\" xmlns:u=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\"> <s:Header>  <a:Action s:mustUnderstand=\"1\">http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue</a:Action>  <a:ReplyTo> <a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>  </a:ReplyTo> <a:To s:mustUnderstand=\"1\">https://login.microsoftonline.com/extSTS.srf</a:To> <o:Security s:mustUnderstand=\"1\"  xmlns:o=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\"> <o:UsernameToken>  <o:Username>%s</o:Username>  <o:Password>%s</o:Password> </o:UsernameToken>  </o:Security> </s:Header><s:Body><t:RequestSecurityToken xmlns:t=\"http://schemas.xmlsoap.org/ws/2005/02/trust\"><wsp:AppliesTo xmlns:wsp=\"http://schemas.xmlsoap.org/ws/2004/09/policy\"><a:EndpointReference><a:Address>" + sharePointProperties.getEndpoint() + "</a:Address></a:EndpointReference></wsp:AppliesTo><t:KeyType>http://schemas.xmlsoap.org/ws/2005/05/identity/NoProofKey</t:KeyType>  <t:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</t:RequestType> <t:TokenType>urn:oasis:names:tc:SAML:1.0:assertion</t:TokenType></t:RequestSecurityToken></s:Body></s:Envelope>";
        return String.format(envelopeTemplate, sharePointProperties.getUsername(), sharePointProperties.getPassword());
    }

    @Cacheable(Const.CACHE_NAME_COOKIE)
    public List<String> getSignInCookies(String securityToken) throws TransformerException, URISyntaxException {
        RequestEntity<String> requestEntity = new RequestEntity<>(securityToken, HttpMethod.POST, new URI(sharePointProperties.getEndpoint() + "/_forms/default.aspx?wa=wsignin1.0"));
        ResponseEntity<String> responseEntity = restTemplate.exchange(requestEntity, String.class);
        HttpHeaders headers = responseEntity.getHeaders();
        List<String> cookies = headers.get("Set-Cookie");
        if (CollectionUtils.isEmpty(cookies)) {
            throw new SharePointSignInException("Unable to sign in: no cookies returned in response");
        }
        log.debug("SharePoint respond with cookies: {}", Joiner.on(", ").join(cookies));
        return cookies;
    }

    public String getFormDigestValue(List<String> cookies) throws IOException, URISyntaxException, TransformerException, JSONException {
        MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
        headers.add("Cookie", Joiner.on(';').join(cookies));
        headers.add("Accept", "application/json;odata=verbose");
        headers.add("X-ClientService-ClientTag", "SDK-JAVA");
        RequestEntity<String> requestEntity = new RequestEntity<>(headers, HttpMethod.POST, new URI(sharePointProperties.getEndpoint() + "/_api/contextinfo"));
        ResponseEntity<String> responseEntity = restTemplate.exchange(requestEntity, String.class);
        JSONObject json = new JSONObject(responseEntity.getBody());
        return json.getJSONObject("d")
                .getJSONObject("GetContextWebInformation")
                .getString("FormDigestValue");
    }

    public Long parseExecutionDateTime(Date dateTime) {
        if (dateTime == null)
            return null;
        final Calendar cal = Calendar.getInstance();
        cal.setTime(dateTime);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime().getTime();
    }

}

此服务中的方法应如下调用:

package com.waveaccess.someproject.commons.service;

import com.google.common.base.Joiner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.net.URI;
import java.util.Date;
import java.util.List;

/**
 * @author Maksim Kanev
 */
@Service
public class SharePointService {

    private static final Logger log = LoggerFactory.getLogger(SharePointService.class);

    @Autowired
    private SharePointServiceCached serviceCached;

    @Autowired
    private RestTemplate restTemplate;

    public String performHttpRequest(HttpMethod method, String path) throws Exception {
        Long executionDateTime = serviceCached.parseExecutionDateTime(new Date());
        String securityToken = serviceCached.receiveSecurityToken(executionDateTime);
        List<String> cookies = serviceCached.getSignInCookies(securityToken);
        MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
        headers.add("Cookie", Joiner.on(';').join(cookies));
        RequestEntity<String> requestEntity = new RequestEntity<>(headers, method, new URI(path));
        ResponseEntity<String> responseEntity = restTemplate.exchange(requestEntity, String.class);
        String responseBody = responseEntity.getBody();
        log.debug(responseBody);
        return responseBody;
    }

    public String performHttpRequest(String path, String json, boolean isUpdate, boolean isWithDigest) throws Exception {
        Long executionDateTime = serviceCached.parseExecutionDateTime(new Date());
        String securityToken = serviceCached.receiveSecurityToken(executionDateTime);
        List<String> cookies = serviceCached.getSignInCookies(securityToken);
        String formDigestValue = serviceCached.getFormDigestValue(cookies);
        MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
        headers.add("Cookie", Joiner.on(';').join(cookies));
        headers.add("Content-type", "application/json;odata=verbose");
        if (isWithDigest) {
            headers.add("X-RequestDigest", formDigestValue);
        }
        if (isUpdate) {
            headers.add("X-HTTP-Method", "MERGE");
            headers.add("IF-MATCH", "*");
        }
        RequestEntity<String> requestEntity = new RequestEntity<>(json, headers, HttpMethod.POST, new URI(path));
        ResponseEntity<String> responseEntity = restTemplate.exchange(requestEntity, String.class);
        String responseBody = responseEntity.getBody();
        log.debug(responseBody);
        return responseBody;
    }

    public String attachFile(String path, byte[] file) throws Exception {
        Long executionDateTime = serviceCached.parseExecutionDateTime(new Date());
        String securityToken = serviceCached.receiveSecurityToken(executionDateTime);
        List<String> cookies = serviceCached.getSignInCookies(securityToken);
        String formDigestValue = serviceCached.getFormDigestValue(cookies);
        MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
        headers.add("Cookie", Joiner.on(';').join(cookies));
        headers.add("X-RequestDigest", formDigestValue);
        headers.add("content-length", String.valueOf(file.length));
        RequestEntity<byte[]> requestEntity = new RequestEntity<>(file, headers, HttpMethod.POST, new URI(path));
        ResponseEntity<String> responseEntity = restTemplate.exchange(requestEntity, String.class);
        String responseBody = responseEntity.getBody();
        log.debug(responseBody);
        return responseBody;
    }

}

XPathExpressionFactoryBean的配置:

package com.waveaccess.someproject.commons.config;

import com.waveaccess.someproject.commons.config.properties.SharePointProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.xml.xpath.XPathExpressionFactoryBean;

import java.util.HashMap;
import java.util.Map;

/**
 * @author Maksim Kanev
 */
@Configuration
@EnableConfigurationProperties({SharePointProperties.class})
public class SharePointConfiguration {

    @Bean
    public XPathExpressionFactoryBean securityTokenExpressionFactoryBean() {
        XPathExpressionFactoryBean xPathExpressionFactoryBean = new XPathExpressionFactoryBean();
        xPathExpressionFactoryBean.setExpression("/S:Envelope/S:Body/wst:RequestSecurityTokenResponse/wst:RequestedSecurityToken/wsse:BinarySecurityToken");

        Map<String, String> namespaces = new HashMap<>();
        namespaces.put("S", "http://www.w3.org/2003/05/soap-envelope");
        namespaces.put("wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
        namespaces.put("wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");
        namespaces.put("wsa", "http://www.w3.org/2005/08/addressing");
        namespaces.put("wst", "http://schemas.xmlsoap.org/ws/2005/02/trust");
        xPathExpressionFactoryBean.setNamespaces(namespaces);
        return xPathExpressionFactoryBean;
    }
}

最后<code>SharePointProperties</code>:

package com.waveaccess.someproject.commons.config.properties;

import org.springframework.boot.context.properties.ConfigurationProperties;

/**
 * @author Maksim Kanev
 */
@ConfigurationProperties("sharepoint")
public class SharePointProperties {

    private String username;
    private String password;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}
 类似资料:
  • 我想访问日历RestAPI。我已经创建了azure多租户应用程序,并对其进行了配置。 我尝试获取对资源“https://outlook.office365.com/”的访问令牌,但出现错误 “AADSTS50001:资源'https://outlook.office365.com/'已禁用。 注意:我在azure帐户的“其他应用程序的权限”部分中找不到“Office 365 Exchange On

  • 你能告诉我Office365 REST API和EWS Java API之间的区别吗? 我为REST API搜索Java库,但没有可用的库。 两个月前,我在ews java api中提出了一个问题,但仍然没有得到他们的任何回应。 您能否建议任何可靠的解决方案来使用office365 API从Java应用程序。 使用我们需要注册我们的应用程序与Azure,我们可以重新Giter是免费的还是付费的。如

  • 我们的一个客户正在使用office365组,我们希望实现以编程方式管理该组内的文件。 我们正在使用SharePoint API来管理Office365站点中的其他文件,但我们无法确定如何为Office365组做到这一点。 我们尝试了图形API(即调用<代码>https://graph.microsoft.com/v1.0/groups/ 通过查看组在Office365中是如何实现的,看起来它们只是

  • 我的目标是编写一些代码,使Office 365用户能够通过REST API访问OneDrive中的文件。我已在Azure AD(Web应用程序/单租户)中注册了一个应用程序,并有一个重定向URI来接收OAuth令牌。我想使用“OAuth委托用户身份”场景。为了了解它的工作原理,我在这里使用了“Office 365 OAuth沙盒”:https://oauthplay.azurewebsites.n

  • 我需要通过REST API访问域中的所有用户文件。我只能通过通过正常OAUTH流授予的访问令牌访问域用户的文件。 我发现了这篇文章:使用Office 365邮件、日历和联系人API(OAuth2客户端凭据流)构建守护程序或服务应用程序 本文仅提及邮件、日历和联系人API。是否支持文件API?

  • 我有一个新的Office365 Small Business订阅,想知道如何最好地将联系人与自定义的内部数据库应用程序同步。 因此,如果我想通过Azure Active Directory图形客户端库访问Office365帐户中的Azure Active Directory,我应该在哪里注册应用程序,获取密钥--以及连接到哪个主机?