用于访问令牌的Outlook API在Java Spring中返回400错误请求

时间:2017-09-05 17:55:12

标签: java spring outlook-api

  • 代码似乎没有任何错误。
  • 这是一个测试应用程序,所有ID都可用。
  • 在函数getToken()中,可以选择取消阻塞行调用 getScopes()并进一步尝试。
  • 我有一个带按钮的index.jsp。
  • 按下按钮" o授权"被激活以生成代码和id_token。
  • 我能够登录,生成代码和id_token。
  • 这些值显示在" authtoken.jsp"它有一个按钮。
  • 按下按钮发布到/common/oauth2/v2.0/token。
  • 在此阶段,Microsoft页面上显示400错误请求。

我不确定出了什么问题:

import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.util.UriComponentsBuilder;


@Controller
public class IndexController {

    //all oauth2 urls
    private static final String authority = "https://login.microsoftonline.com";
    private static final String authorizeUrl = authority + "/common/oauth2/v2.0/authorize";
    private static final String tokenUrl = authority + "/common/oauth2/v2.0/token";
    private static final String redirectUrl = "http://localhost:8080/OutlookProfiles/authtoken";
    private static final String reTokenUrl = "http://localhost:8080/OutlookProfiles/showToken";

    //credentials
    private static final String appId = "7414b3a3-26f1-4928-9d0b-7060d01dd41c";
    private static final String appPassword = "cQg9F0EaxuaErNp2YEgYaz8";

    private static final String[] scopes = { 
                "openid", 
                "offline_access",
                "profile", 
                "User.Read",
                "Contacts.Read",
                "Mail.Read"
              };


    @RequestMapping(value = "/index", method = RequestMethod.GET)
    public String index(Model model, HttpServletRequest request, HttpServletResponse response){

        UUID state = UUID.randomUUID();
        UUID nonce = UUID.randomUUID();

        // Save the state and nonce in the session so we can
        // verify after the auth process redirects back

        HttpSession session = request.getSession();
        session.setAttribute("expected_state", state);
        session.setAttribute("expected_nonce", nonce);

        return "index";
    }

    @RequestMapping(value = "/oauthorize", method = RequestMethod.POST)
    public void oauthorize(Model model, HttpServletRequest servletRequest, HttpServletResponse servletResponse) {

        try{

        UUID state = UUID.randomUUID();
        UUID nonce = UUID.randomUUID();

          HttpSession session = servletRequest.getSession();
          session.setAttribute("expected_state", state);
          session.setAttribute("expected_nonce", nonce);
          session.setAttribute("error", null);

        UriComponentsBuilder urlBuilder = UriComponentsBuilder.fromHttpUrl(authorizeUrl);
        urlBuilder.queryParam("client_id", appId);
        urlBuilder.queryParam("redirect_uri", redirectUrl);
        urlBuilder.queryParam("response_type", "code id_token");
        urlBuilder.queryParam("scope", getScopes());
        urlBuilder.queryParam("state", state);
        urlBuilder.queryParam("nonce", nonce);
        urlBuilder.queryParam("response_mode", "form_post");

        String locationUri = urlBuilder.toUriString();
        System.out.println(locationUri);

        servletResponse.sendRedirect(locationUri);

        }catch(Exception e){
            e.printStackTrace();
        }

    }


    @RequestMapping(value = "/authtoken", method = RequestMethod.POST)
    public String authorize(
                @RequestParam("code") String code, 
                @RequestParam("id_token") String idToken,
                @RequestParam("state") UUID state, 
                HttpServletRequest servletRequest, 
                HttpServletResponse servletResponse) {

        // Get the expected state value from the session
        HttpSession session = servletRequest.getSession();
        UUID expectedState = (UUID) session.getAttribute("expected_state");
        UUID expectedNonce = (UUID) session.getAttribute("expected_nonce");


        String strState = state.toString().trim().toLowerCase();
        String strExState = expectedState.toString().trim().toLowerCase();


        // Make sure that the state query parameter returned matches
        // the expected state
        if (strState.equals(strExState)){
          session.setAttribute("authCode", code);
          session.setAttribute("idToken", idToken);
          System.out.println("Expectedstate : NO Error");
        }else {
          session.setAttribute("error", "Unexpected state returned from authority.");
          System.out.println("\n\nUnexpected state returned from authority.");
        }

        return "authtoken";
    }

    @RequestMapping(value = "/getToken", method = RequestMethod.POST)
    public void getToken(
            HttpServletRequest servletRequest, 
            HttpServletResponse servletResponse) {

        try{

        HttpSession session = servletRequest.getSession();
        String strCode = (String) session.getAttribute("authCode");

        UriComponentsBuilder urlBuilder = UriComponentsBuilder.fromHttpUrl(tokenUrl);
        urlBuilder.queryParam("client_id", appId);
        urlBuilder.queryParam("client_secret", appPassword);
        urlBuilder.queryParam("code", strCode);
        urlBuilder.queryParam("redirect_uri", redirectUrl);
        urlBuilder.queryParam("grant_type", "authorization_code");
        urlBuilder.queryParam("scope", getScopes());

        String locationUri = urlBuilder.toUriString();
        System.out.println("getToken : " + locationUri);

        servletResponse.setHeader("Content-Type", "application/x-www-form-urlencoded");

        servletResponse.sendRedirect(locationUri);

        }catch(Exception e){
            e.printStackTrace();
        }
    }

    @RequestMapping(value = "/showToken", method = RequestMethod.POST)
    public String showToken(
            @RequestParam("token_type") String code, 
            @RequestParam("expires_in") String idToken,
            @RequestParam("access_token") String accessToken, 
            //@RequestParam("scope") String paramScope,
            HttpServletRequest servletRequest, 
            HttpServletResponse servletResponse) {

        return "getToken";

    }

    @RequestMapping("/logout")
    public String logout(HttpServletRequest request) {
      HttpSession session = request.getSession();
      session.invalidate();
      return "index";
    }

    private static String getScopes() {
            StringBuilder sb = new StringBuilder();
            for (String scope: scopes) {
              sb.append(scope + " ");
            }

            String strscope = sb.toString().trim();
            System.out.println(strscope);

            return strscope;
    }
}

400错误无缘无故地弄乱了我的脑袋。

1 个答案:

答案 0 :(得分:1)

  • 访问令牌的Microsoft Outlook API端点:https://login.microsoftonline.com/common/oauth2/v2.0/token 期望基于表单的POST,即application / x-www-form-urlencoded。
  • 这意味着所有输入参数都应该基于表单而不是追加网址
  • 从技术上讲,使用UriComponentsBuilder
  • 的代码是错误的
  • 代码应该使用基于JSON或基于表单的方法,使用HttpClient和HttpPost,或者使用基于OKHttpClient和RequestBody的OKHttp3。

我很快就会在这里发布工作代码。

...这是工作代码......

import java.util.List;
import java.util.ArrayList;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpServletResponse;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.util.UriComponentsBuilder;


@Controller
public class IndexController {

    //all oauth2 urls
    private static final String authority = "https://login.microsoftonline.com";
    private static final String authorizeUrl = authority + "/common/oauth2/v2.0/authorize";
    private static final String tokenUrl = authority + "/common/oauth2/v2.0/token";
    private static final String redirectUrl = "http://localhost:8080/OutlookProfiles/authtoken";
    private static final String reTokenUrl = "http://localhost:8080/OutlookProfiles/showToken";

    //credentials
    private static final String appId = "7414b3a3-26f1-4928-9d0b-7060d01dd41c";
    private static final String appPassword = "cQg9F0EaxuaErNp2YEgYaz8";

    private static final String[] scopes = { 
                "openid", 
                "offline_access",
                "profile", 
                "User.Read",
                "Contacts.Read",
                "Mail.Read"
              };


    @RequestMapping(value = "/index", method = RequestMethod.GET)
    public String index(Model model, HttpServletRequest request, HttpServletResponse response){

        UUID state = UUID.randomUUID();
        UUID nonce = UUID.randomUUID();

        // Save the state and nonce in the session so we can
        // verify after the auth process redirects back

        HttpSession session = request.getSession();
        session.setAttribute("expected_state", state);
        session.setAttribute("expected_nonce", nonce);

        return "index";
    }

    @RequestMapping(value = "/oauthorize", method = RequestMethod.POST)
    public void oauthorize(Model model, HttpServletRequest servletRequest, HttpServletResponse servletResponse) {

        try{

        UUID state = UUID.randomUUID();
        UUID nonce = UUID.randomUUID();

          HttpSession session = servletRequest.getSession();
          session.setAttribute("expected_state", state);
          session.setAttribute("expected_nonce", nonce);
          session.setAttribute("error", null);

        UriComponentsBuilder urlBuilder = UriComponentsBuilder.fromHttpUrl(authorizeUrl);
        urlBuilder.queryParam("client_id", appId);
        urlBuilder.queryParam("redirect_uri", redirectUrl);
        urlBuilder.queryParam("response_type", "code id_token");
        urlBuilder.queryParam("scope", getScopes());
        urlBuilder.queryParam("state", state);
        urlBuilder.queryParam("nonce", nonce);
        urlBuilder.queryParam("response_mode", "form_post");

        String locationUri = urlBuilder.toUriString();
        System.out.println(locationUri);

        servletResponse.sendRedirect(locationUri);

        }catch(Exception e){
            e.printStackTrace();
        }

    }


    @RequestMapping(value = "/authtoken", method = RequestMethod.POST)
    public String authorize(
                @RequestParam("code") String code, 
                @RequestParam("id_token") String idToken,
                @RequestParam("state") UUID state, 
                HttpServletRequest servletRequest, 
                HttpServletResponse servletResponse) {

        // Get the expected state value from the session
        HttpSession session = servletRequest.getSession();
        UUID expectedState = (UUID) session.getAttribute("expected_state");
        UUID expectedNonce = (UUID) session.getAttribute("expected_nonce");


        String strState = state.toString().trim().toLowerCase();
        String strExState = expectedState.toString().trim().toLowerCase();


        // Make sure that the state query parameter returned matches
        // the expected state
        if (strState.equals(strExState)){
          session.setAttribute("authCode", code);
          session.setAttribute("idToken", idToken);
          System.out.println("Expectedstate : NO Error");
        }else {
          session.setAttribute("error", "Unexpected state returned from authority.");
          System.out.println("\n\nUnexpected state returned from authority.");
        }

        return "authtoken";
    }

    @RequestMapping(value = "/getToken", method = RequestMethod.POST)
    public void getToken(
            HttpServletRequest servletRequest, 
            HttpServletResponse servletResponse) {

        try{

        HttpSession session = servletRequest.getSession();
        String strCode = (String) session.getAttribute("authCode");

        HttpClient httpClient = HttpClients.createDefault(); 
        HttpPost httpPost = new HttpPost(tokenUrl); 
        httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");
           List <BasicNameValuePair> params = new ArrayList<>();
           params.add(new BasicNameValuePair("client_id", appId));
           params.add(new BasicNameValuePair("client_secret", appPassword));
           params.add(new BasicNameValuePair("redirect_uri", redirectUrl));
           params.add(new BasicNameValuePair("code", strCode));
           params.add(new BasicNameValuePair("grant_type", "authorization_code"));

           httpPost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
           httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");

           HttpResponse httpResponse = httpClient.execute(httpPost);
           org.apache.http.HttpEntity entity = httpResponse.getEntity();
           //String theString = IOUtils.toString(entity.getContent(), "UTF-8");
           String strResponse = EntityUtils.toString(entity, "UTF-8");
           System.out.println(strResponse);
           strResponse = "{\"response\":["+strResponse+"]}";
           System.out.println(strResponse);

           JSONObject result = new JSONObject(strResponse); //Convert String to JSON Object
           JSONArray tokenList = result.getJSONArray("response");
           JSONObject objJson = tokenList.getJSONObject(0);
           String accessToken = objJson.getString("access_token");
           System.out.println(accessToken);

           session.setAttribute("accessToken", accessToken);

        }catch(Exception e){
            e.printStackTrace();
        }
    }

    @RequestMapping(value = "/showToken", method = RequestMethod.POST)
    public String showToken(
            @RequestParam("token_type") String code, 
            @RequestParam("expires_in") String idToken,
            @RequestParam("access_token") String accessToken, 
            //@RequestParam("scope") String paramScope,
            HttpServletRequest servletRequest, 
            HttpServletResponse servletResponse) {

        return "getToken";

    }

    @RequestMapping("/logout")
    public String logout(HttpServletRequest request) {
      HttpSession session = request.getSession();
      session.invalidate();
      return "index";
    }

    private static String getScopes() {
            StringBuilder sb = new StringBuilder();
            for (String scope: scopes) {
              sb.append(scope + " ");
            }

            String strscope = sb.toString().trim();
            System.out.println(strscope);

            return strscope;
    }
}