Java Servlets中Google OAuth弹窗无法通过Window.close()关闭
Hey there! Let's tackle this popup closing issue you're facing with your Google OAuth flow. The core problem boils down to a cross-origin security restriction plus a couple of small code gaps. Let's break it down and fix it step by step.
Why the Popup Won't Close
When you use Desktop.getDesktop().browse() to open your local google_oauth.html, it loads via the file:// protocol. But your REDIRECT URL uses http://localhost:8080—these are two distinct origins. Browsers block scripts from a file:// page accessing the document of a http:// page for security reasons, so your try block throws an error, gets caught, and never reaches the win.close() line.
On top of that, your gup function doesn't return the extracted token value, which would break subsequent authentication steps even if the popup did close.
Fixes to Implement
1. Load google_oauth.html via HTTP Instead of Local File
Instead of opening the local file directly from your Servlet, redirect the user to the HTTP-accessible version of the page. This ensures both the parent page and OAuth popup share the same origin (http://localhost:8080), eliminating the cross-origin block.
Update your Servlet code:
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // Redirect to the hosted google_oauth.html instead of opening a local file String oauthPageUrl = request.getContextPath() + "/google_oauth.html"; response.sendRedirect(oauthPageUrl); }
2. Fix the gup Function to Return Extracted Values
Your current gup function doesn't return the parameter it extracts, leaving acToken, tokenType, and expiresIn undefined. Update it like this:
function gup(url, name) { name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]"); var regexS = "[\\#&]"+name+"=([^&#]*)"; var regex = new RegExp( regexS ); var results = regex.exec(url); // Return the matched value or null if not found return results === null ? null : results[1]; }
3. Ensure Reliable Popup Closing
Add checks to handle manual popup closure and clean up the interval properly. Here's the updated login function:
function login() { var win = window.open(_url, "windowname1", 'width=800, height=600'); if (!win) { alert("Please allow popups for this site to proceed!"); return; } var pollTimer = window.setInterval(function() { try { // Exit if user closed the popup manually if (win.closed) { window.clearInterval(pollTimer); return; } var currentUrl = win.document.URL; if (currentUrl.indexOf(REDIRECT) !== -1) { window.clearInterval(pollTimer); var acToken = gup(currentUrl, 'access_token'); var tokenType = gup(currentUrl, 'token_type'); var expiresIn = gup(currentUrl, 'expires_in'); win.close(); if (acToken) { validateToken(acToken); } else { console.error("Failed to extract access token from redirect URL"); } } } catch(e) { console.log("Cross-origin check error (should not occur with HTTP setup)", e); } }, 500); }
Bonus: Simplify Your Flow (Optional)
You can skip the Servlet entirely by having the "Sign In With Google" button in index.jsp call the login() function directly. This is a more standard client-side OAuth flow:
Update the form in index.jsp to a JS-triggered button:
<button onclick="login()">Sign In With Google</button> <script> var OAUTHURL = 'https://accounts.google.com/o/oauth2/auth?'; var VALIDURL = 'https://www.googleapis.com/oauth2/v1/tokeninfo?access_token='; var SCOPE = 'https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email'; var CLIENTID = '778647136201-d9trubpsuokohuj9a0c9bgufpo1qvqtf.apps.googleusercontent.com'; var REDIRECT = 'http://localhost:8080/Website/main_page' var TYPE = 'token'; var _url = OAUTHURL + 'scope=' + SCOPE + '&client_id=' + CLIENTID + '&redirect_uri=' + REDIRECT + '&response_type=' + TYPE; // Include the updated login, gup, validateToken, and getUserInfo functions here </script>
内容的提问来源于stack exchange,提问作者XzibitGG

