java - 向 Google 进行身份验证时授权无效
问题描述
我正在尝试连接到 Google Calendar API。我已按照 Java 的 Google 日历快速入门中的步骤进行操作
{ "error" : "invalid_grant", "error_description" : "错误请求" }
你能告诉我如何调试这个吗?不幸的是,错误消息没有帮助,我已经尝试了关于堆栈溢出或其他地方的这个特定错误的所有方法
每次我为不同的凭据获得相同的访问令牌时:
访问令牌:{user=Class{accessToken=null, refreshToken="" expirationTimeMilliseconds=null}}
代码:
public class CalendarServiceImpl implements CalendarService {
public static final String APPLICATION_NAME = "GoogleCalenderApi";
public static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
public static final String TOKENS_DIRECTORY_PATH = "/data.json";
public static final List<String> SCOPES = Collections.singletonList(CalendarScopes.CALENDAR);
public static final String CREDENTIALS_FILE_PATH = "/data.json";
public Credential getCredentials(final NetHttpTransport HTTP_TRANSPORT, HttpServletRequest request)
throws IOException {
InputStream in = CalendarServiceImpl.class.getResourceAsStream(CREDENTIALS_FILE_PATH);
if (in == null) {
log.info("Resource not found: " + CREDENTIALS_FILE_PATH);
throw new FileNotFoundException("Resource not found: " + CREDENTIALS_FILE_PATH);
}
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(HTTP_TRANSPORT, JSON_FACTORY,
clientSecrets, SCOPES)
.setDataStoreFactory(new FileDataStoreFactory(new java.io.File(TOKENS_DIRECTORY_PATH)))
.setAccessType("offline")
.build();
System.out.println("Access token: " + flow.getCredentialDataStore());
LocalServerReceiver receiver = new LocalServerReceiver.Builder().setPort(80)
.build();
return new AuthorizationCodeInstalledApp(flow, receiver).authorize("user");
}
public void createCalendarEvent(String candidateMailId, String companyEmailId, DateTime fromTime, DateTime toTime,
String summary, String description, HttpServletRequest request)
throws GeneralSecurityException, IOException {
final NetHttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
Event event = new Event().setSummary(summary).setLocation("Test").setDescription(description);
EventDateTime start = new EventDateTime().setDateTime(fromTime).setTimeZone("Asia/Kolkata");
event.setStart(start);
EventDateTime end = new EventDateTime().setDateTime(toTime).setTimeZone("Asia/Kolkata");
event.setEnd(end);
String[] recurrence = new String[] { "RRULE:FREQ=DAILY" };
event.setRecurrence(Arrays.asList(recurrence));
EventAttendee[] attendees = new EventAttendee[] { new EventAttendee().setEmail(candidateMailId),
new EventAttendee().setEmail(companyEmailId) };
event.setAttendees(Arrays.asList(attendees));
EventReminder[] reminderOverrides = new EventReminder[] { new EventReminder().setMethod("email").setMinutes(10),
new EventReminder().setMethod("popup").setMinutes(10), };
Event.Reminders reminders = new Event.Reminders().setUseDefault(false)
.setOverrides(Arrays.asList(reminderOverrides));
event.setReminders(reminders);
// Build service account credential.
Credential credential = getCredentials(HTTP_TRANSPORT, request);
log.info("got credential:" + event);
Calendar service = new Calendar.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential)
.setApplicationName(APPLICATION_NAME).build();
String calendarId = "primary";
try {
System.out.printf("Event started" + event);
event = service.events().insert(calendarId, event).setSendUpdates("all").execute();
} catch (IOException e) {
log.info("event IOException:" + e);
e.getMessage();
}
log.info("Event created:" + event.getHtmlLink());
}
}
解决方案
您似乎正在使用 AuthorizationCodeInstalledApp ,因为它统计的是已安装的应用程序。对于 Web 应用程序,您需要使用 AuthorizationCodeFlow。
官方示例可以在这里找到 Web server application
public class CalendarServletSample extends AbstractAuthorizationCodeServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException {
// do stuff
}
@Override
protected String getRedirectUri(HttpServletRequest req) throws ServletException, IOException {
GenericUrl url = new GenericUrl(req.getRequestURL().toString());
url.setRawPath("/oauth2callback");
return url.build();
}
@Override
protected AuthorizationCodeFlow initializeFlow() throws IOException {
return new GoogleAuthorizationCodeFlow.Builder(
new NetHttpTransport(), JacksonFactory.getDefaultInstance(),
"[[ENTER YOUR CLIENT ID]]", "[[ENTER YOUR CLIENT SECRET]]",
Collections.singleton(CalendarScopes.CALENDAR)).setDataStoreFactory(
DATA_STORE_FACTORY).setAccessType("offline").build();
}
@Override
protected String getUserId(HttpServletRequest req) throws ServletException, IOException {
// return user ID
}
}
public class CalendarServletCallbackSample extends AbstractAuthorizationCodeCallbackServlet {
@Override
protected void onSuccess(HttpServletRequest req, HttpServletResponse resp, Credential credential)
throws ServletException, IOException {
resp.sendRedirect("/");
}
@Override
protected void onError(
HttpServletRequest req, HttpServletResponse resp, AuthorizationCodeResponseUrl errorResponse)
throws ServletException, IOException {
// handle error
}
@Override
protected String getRedirectUri(HttpServletRequest req) throws ServletException, IOException {
GenericUrl url = new GenericUrl(req.getRequestURL().toString());
url.setRawPath("/oauth2callback");
return url.build();
}
@Override
protected AuthorizationCodeFlow initializeFlow() throws IOException {
return new GoogleAuthorizationCodeFlow.Builder(
new NetHttpTransport(), JacksonFactory.getDefaultInstance()
"[[ENTER YOUR CLIENT ID]]", "[[ENTER YOUR CLIENT SECRET]]",
Collections.singleton(CalendarScopes.CALENDAR)).setDataStoreFactory(
DATA_STORE_FACTORY).setAccessType("offline").build();
}
@Override
protected String getUserId(HttpServletRequest req) throws ServletException, IOException {
// return user ID
}
}
AuthorizationCodeFlow 在运行代码的机器中打开同意浏览器窗口。当您将某些东西作为网站运行时,它需要在客户端计算机上打开,以便用户可以看到它。
推荐阅读
- c# - 失去互联网连接后,单声道上的 Webrequest 无法恢复
- json - 使用 powershell 正确格式化 JSON
- angular - .subscribe() 方法中所做的更改未反映在它或模板中
- angular - 如何从Angular中的动态输入中获取值?
- java - 是否有任何库可以使用 java 或 springboot 或 nodejs 将多个 json 模式组合成单个模式
- kendo-ui - 具有许多编辑模板的剑道列表视图
- python - 如何在 django 中使用外部数据库?
- c++ - 使用滑动窗口算法和链表在c ++中找到最长不重复字符的子串的长度。(leetcode)
- php - 上传照片而不更改其原始大小不起作用
- apache - 将客户端 IP 更改为 API 请求的代理 IP