java - tienes - Spring: la autenticación de Google redirect_uri_mismatch y la URL no se abren en el navegador
como puedo autenticar mi cuenta de google play (2)
Estoy trabajando en una aplicación Spring-MVC que se ejecuta en Tomcat en la que me gustaría usar la funcionalidad de unidad de Google. Intenté con una cuenta de servicio en mi máquina local y no tuve problemas. Pero cuando cargué el código en el servidor, la URL del navegador no se abrirá. Entonces pensé, no debería usar una cuenta de servicio, debería usar una cuenta de aplicación web normal. Ahora cuando hago eso, obtengo un redirect_uri_mismatch.
No entiendo una cosa, estoy configurando la URL de redirección en flujo, en el JSON, ¿por qué en la tierra está obteniendo el redirect_url con números de puerto aleatorios? Si cambio el número de puerto en la URL del navegador, funciona bien. Pero aún en el servidor no abrirá la URL del navegador, puedo verlo en los registros de Tomcat, pero la maldita cosa no abre la URL.
Aquí está mi URL de redirección de la aplicación de 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
Aquí está mi 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"]
}}
Y aquí está el código donde intento autenticar:
@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;
}
Esto me molesta mucho ya que estoy configurando la URL de redireccionamiento, y simplemente se ignora y por qué en la Tierra no se abrirá una pestaña del navegador cuando la aplicación se implementa en el servidor.
El problema de actualización de Spring también se corrigió, el código a continuación se puede usar para la autorización de GoogleDrive en un servidor con tomcat u otros.
@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);
}
}
Método del controlador:
@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 solo tiene un botón para hacer clic en la URL.
En lugar de usar:
Credential credential = new AuthorizationCodeInstalledApp( flow,
new LocalServerReceiver).authorize("user");
Utilizar
LocalServerReceiver localReceiver = new LocalServerReceiver.
Builder().setPort(XXXX).build();
para configurar un número de puerto estático
Credential credential = new AuthorizationCodeInstalledApp( flow,
localReceiver).authorize("user");
aunque no podrá cambiar la URL de redirección, sin embargo, puede configurar el host y el puerto. Para cambiar el uso del host .setHost()
método
También puedes usar el constructor predeterminado como:
Credential credential = new AuthorizationCodeInstalledApp( flow,
new LocalServerReceiver("Host", XXXX).authorize("user");
Específicamente, obtiene puertos aleatorios porque está utilizando LocalServerReceiver , que inicia una instancia de embarcadero en un puerto libre para recibir un código de autenticación.
En un nivel superior, parece que está desarrollando una aplicación de servidor web , pero está tratando de usar Google OAuth como si fuera una aplicación instalada . Si realmente está haciendo una aplicación de servidor web, debe usar el nombre de host de su servidor en lugar de localhost en su URL de devolución de llamada, proporcionando un enlace para que el usuario final se autentique usando flow.newAuthorizationUrl () , y haga que su devolución de llamada obtenga el token usando flow.newTokenRequest (String) . También asegúrese de que la ID del cliente que creó en su consola sea del tipo de aplicación web, o obtendrá errores redirect_uri_mismatch . Un ejemplo completo de cómo hacer esto se puede encontrar aquí .