【问题标题】:Spring : Google authentication redirect_uri_mismatch and URL wont open on browserSpring:Google 身份验证 redirect_uri_mismatch 和 URL 不会在浏览器上打开
【发布时间】:2015-09-16 23:36:09
【问题描述】:

我正在开发一个在 tomcat 上运行的 Spring-MVC 应用程序,我想在其中使用 Google 驱动器功能。我尝试在本地计算机上使用服务帐户,但没有任何问题。但是当我在服务器上上传代码时,浏览器 URL 不会打开。然后我想,我不应该使用服务帐户,我应该使用普通的 Web 应用程序帐户。现在,当我这样做时,我得到了一个 redirect_uri_mismatch。

我不明白一件事,我在 JSON 中设置重定向 URL,为什么它会获取带有随机端口号的 redirect_url。如果我更改浏览器 URL 中的端口号,它可以正常工作。但是仍然在服务器上它不会打开浏览器的 url,我可以在 tomcat 日志中看到它,但是该死的东西没有打开 URL。

这是我在 Google 应用中的重定向网址:

http://localhost/authorizeuser
http://localhost:8080/
http://localhost:8080
http://localhost
http://localhost:8080/Callback
https://testserver.net/Callback
http://testserver.net/Callback
http://127.0.0.1

这是我的 client_secret.json :

{"web": {
    "client_id": "clientid",
    "auth_uri": "https://accounts.google.com/o/oauth2/auth",
    "token_uri": "https://accounts.google.com/o/oauth2/token",
    "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
    "client_email": "clientemailstuff",
    "client_x509_cert_url": "certurlstuff",
    "client_secret": "itsasecret",
    "redirect_uris": ["http://localhost:8080/","http://localhost:8080"],
    "javascript_origins": ["https://testserver.net", "http://testserver.net","http://localhost:8080"]
}}

这是我要验证的代码:

 @Override
    public Credential authorize() throws IOException {
        InputStream in =
                DriveQuickstartImpl.class.getResourceAsStream("/client_secret.json");
        GoogleClientSecrets clientSecrets =
                GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));

        GoogleAuthorizationCodeFlow flow =
                new GoogleAuthorizationCodeFlow.Builder(
                        HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
                        .setDataStoreFactory(DATA_STORE_FACTORY)
                        .setAccessType("offline")
                        .build();
        flow.newAuthorizationUrl().setState("xyz").setRedirectUri("http://localhost:8080/Callback");
        Credential credential = new AuthorizationCodeInstalledApp(
                flow, new LocalServerReceiver()).authorize("user");

        if(credential!=null && credential.getRefreshToken() != null){
            storeCredentials(credential);
        }
        return credential;
    }

这让我很生气,因为我正在设置重定向 url,它只是被忽略了,为什么在服务器上部署应用程序时浏览器选项卡不会打开。

更新 Spring 问题也已修复,以下代码可用于在带有 tomcat 或其他服务器的服务器上进行 GoogleDrive 授权。

@Service
@Transactional
public class GoogleAuthorization{


    @Autowired
    private DriveQuickstart driveQuickstart;

    private static final String APPLICATION_NAME ="APPNAME";

    private static final java.io.File DATA_STORE_DIR = new java.io.File(
            "/home/deploy/store");

    private static FileDataStoreFactory DATA_STORE_FACTORY;

    private static final JsonFactory JSON_FACTORY =
            JacksonFactory.getDefaultInstance();

    private static HttpTransport HTTP_TRANSPORT;

    private static final List<String> SCOPES =
            Arrays.asList(DriveScopes.DRIVE);

    private static final String clientid = "clientid";
    private static final String clientsecret = "clientsecret";

    private static final String CALLBACK_URI = "http://localhost:8080/getgooglelogin";

    private String stateToken;

    private final GoogleAuthorizationCodeFlow flow;

    public GoogleAuthorization(){
        try {
            HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
            DATA_STORE_FACTORY = new FileDataStoreFactory(DATA_STORE_DIR);

        } catch (GeneralSecurityException | IOException e) {
            e.printStackTrace();
        }

        flow = new GoogleAuthorizationCodeFlow.Builder(HTTP_TRANSPORT,
                JSON_FACTORY, clientid, clientsecret, SCOPES).setAccessType("offline").setApprovalPrompt("force").build();
        generateStateToken();

    }



    /**
     * Builds a login URL based on client ID, secret, callback URI, and scope
     */
    public String buildLoginUrl() {

        final GoogleAuthorizationCodeRequestUrl url = flow.newAuthorizationUrl();

        return url.setRedirectUri(CALLBACK_URI).setState(stateToken).build();
    }

    /**
     * Generates a secure state token
     */
    private void generateStateToken(){
        SecureRandom sr1 = new SecureRandom();
        stateToken = "google;"+sr1.nextInt();
    }

    /**s
     * Accessor for state token
     */
    public String getStateToken(){
        return stateToken;
    }

    /**
     * Expects an Authentication Code, and makes an authenticated request for the user's profile information
     * * @param authCode authentication code provided by google
     */
    public void saveCredentials(final String authCode) throws IOException {

        GoogleTokenResponse response = flow.newTokenRequest(authCode).setRedirectUri(CALLBACK_URI).execute();
        Credential credential = flow.createAndStoreCredential(response, null);
        System.out.println(" Credential access token is "+credential.getAccessToken());
        System.out.println("Credential refresh token is "+credential.getRefreshToken());
// The line below gives me a NPE.
        this.driveQuickstart.storeCredentials(credential);
    }
}

控制器方法:

  @RequestMapping(value = "/getgooglelogin")
    public String getGoogleLogin(HttpServletRequest request, HttpServletResponse response, HttpSession session,Model model) {
// Below guy should be autowired if you want to use Spring. 
        GoogleAuthorization helper = new GoogleAuthorization();

        if (request.getParameter("code") == null
                || request.getParameter("state") == null) {

            model.addAttribute("URL", helper.buildLoginUrl());
            session.setAttribute("state", helper.getStateToken());

        } else if (request.getParameter("code") != null && request.getParameter("state") != null && request.getParameter("state").equals(session.getAttribute("state"))) {
            session.removeAttribute("state");

            try {
                helper.saveCredentials(request.getParameter("code"));
                return "redirect:/dashboard";
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return "newjsp";
    }

newjsp 只有一个按钮可以点击 URL。

【问题讨论】:

  • redirect uri 是发送请求的服务器的位置 www.whatever.com/callback 你的生产服务器不是本地主机。
  • @DaImTo :我同意这一点,但我在凭证中提到的重定向 uri 未被调用。而且我没有发现为正在发出的请求设置重定向 url,代码将其设置为 localhost:randomPortNumber 即使我在 JSON 中指定使用 localhost:8080。
  • 客户端库会为您检测到它是从您发送的位置发送的。您不应该在代码中设置重定向 URI。您应该在 Google Developer 控制台中设置您发送的重定向 uri,这就是您需要做的所有事情。设置您的 ide,使其不会创建随机端口号
  • @DaImTo :好的,但是当我们将war文件部署在运行Apache tomcat但没有使用IDE的服务器上时,也会发生同样的事情。你知道为什么当我们部署war文件时,浏览器URL没有打开,而在本地机器上它正在打开,我需要做哪些修改才能让服务器打开URL。任何想法在 IntelliJ 想法中我都可以指示不要为重定向 URL 调用随机端口号。非常感谢。我对 Google API 完全陌生,不知道发生了什么。
  • 另外,如您所见,我已经配置了正确的端口号:postimg.org/image/r43qpuqsh

标签: java google-api google-oauth google-apps google-api-java-client


【解决方案1】:

具体来说,您获得随机端口是因为您使用LocalServerReceiver,而starts up a jetty instance on a free port 是为了接收授权码。

在更高的级别上,您似乎正在开发一个web server application,但您正在尝试使用 Google OAuth,就好像它是一个 installed application。如果您确实在制作 Web 服务器应用程序,则应在回调 URL 中使用服务器的主机名而不是 localhost,为最终用户提供使用 flow.newAuthorizationUrl() 进行身份验证的链接,并让您的回调使用 @987654326 获取令牌@。还要确保您在console 中创建的客户端ID 是Web 应用程序类型,否则您将get redirect_uri_mismatch errors。可以在here 找到如何执行此操作的完整工作示例。

【讨论】:

  • 我现在将进行更改并回复您。非常感谢。
  • 我的朋友,一切似乎都正常,只是课程没有连接到 Spring。这就是我获得 NPE 的原因。我正在编辑我的主要帖子,请你看看我能做什么。
  • 我刚刚编辑了我的帖子。您能否检查一下我拥有的 GoogleAuthorization 类,在最后一种方法中,我得到了一个 NPE,因为 Spring 没有正确自动装配
  • 所以,问题已经解决,我们正在测试它,一旦完成,我会标记你的答案。再次非常感谢。荣誉。
【解决方案2】:

而不是使用:

Credential credential = new AuthorizationCodeInstalledApp( flow, 
                     new LocalServerReceiver).authorize("user");

使用

LocalServerReceiver localReceiver = new LocalServerReceiver.
                                        Builder().setPort(XXXX).build();

用于设置静态端口号

Credential credential = new AuthorizationCodeInstalledApp( flow,
                                      localReceiver).authorize("user");

虽然您无法更改重定向 url,但是您可以设置主机和端口。 更改主机使用.setHost() 方法

你也可以使用默认构造函数:

Credential credential = new AuthorizationCodeInstalledApp( flow, 
             new LocalServerReceiver("Host", XXXX).authorize("user");

【讨论】:

  • parameterizd 构造函数不公开
猜你喜欢
  • 2018-10-04
  • 1970-01-01
  • 2014-03-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-28
  • 2020-09-19
  • 2018-09-27
相关资源
最近更新 更多