春季:谷歌身份验证重定向和URL不会在浏览器上打开



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

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

以下是我从谷歌应用程序的重定向URL:

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的按钮。

具体来说,您得到的是随机端口,因为您使用的是LocalServerReceiver,它在自由端口上启动一个jetty实例,以便接收身份验证代码。

在更高的级别上,看起来您正在开发一个web服务器应用程序,但您正试图将GoogleOAuth当作一个已安装的应用程序来使用。如果你确实在制作一个web服务器应用程序,你应该在回调URL中使用服务器的主机名,而不是localhost,为最终用户提供一个使用flow.newAuthorizationUrl()进行身份验证的链接,并让你的回调使用flow.newTokenRequest(String)获取令牌。还要确保你在控制台中创建的客户端ID是web应用程序类型,否则您将得到redirect_uri_mismatch错误。关于如何做到这一点,可以在这里找到一个完整的工作示例。

而不是使用:

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");

相关内容

  • 没有找到相关文章

最新更新