Java oauth2 проблема с внедрением внешнего апи
Вот примерная логика приложения:
- Пользователь заходит в приложение через обычную форму Логин+Пароль
- Юзер хочет открыть информацию о его спортивных действиях и заходит в нужную вкладку
- Клиент (флаттер) отправляет его запрос на бэк (джава)
- На бэке с учётом client id и прочего генерируется нужная ссылка и возвращается на фронт
- Фронт перенаправляет пользователя на страницу авторизации
- После авторизации приходит запрос на callback url, где приходит код
- С этим кодом бэк через rest template получает токен
- Сохраняю токен в базе данных
- Через диплинк возвращаю пользователя в мобильное приложение
Проблема возникает на 8 шаге, так как на этот эндпоинт приходит запрос с внешнего апи, я не могу никак определить, к какому пользователю мне прикрепить данный токен (пользователь уже залогинен в приложении и авторизация через классическое Oauth2 не подходит).
Вот код контроллера и сервиса:
@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/strava")
public class StravaController {
private final StravaService stravaService;
@GetMapping("/token/location")
public String getLocation(HttpServletResponse response) throws IOException {
return stravaService.getLocation();
}
@GetMapping("/token/callback")
public String getToken(@RequestParam String code) throws URISyntaxException {
String location = stravaService.getToken(code);
return "<html>\n" + "<header><title>Welcome</title></header>\n" +
"<body>\n" + "<a href=\"" + location + "\">Click</a>" + "</body>\n" + "</html>";
}
}
Проблема возникает, когда я пытаюсь получить текущего пользователя из SecurityContextHolder
:
@Slf4j
@Service
@RequiredArgsConstructor
public class StravaService {
private final StravaTokenRepository stravaTokenRepository;
private final AccountService accountService;
@Value("${strava.client_id}")
private String client_id;
@Value("${strava.client_secret}")
private String client_secret;
@Value("${strava.redirect_uri}")
private String redirect_uri;
@Value("${strava.response_type}")
private String response_type;
@Value("${strava.scope}")
private String scope;
@Value("${strava.grant_type}")
private String grant_type;
@Value("${mobile_app.redirect_uri}")
private String mobileRedirectUri;
private static final String AUTHORIZATION_ENDPOINT = "https://www.strava.com/oauth/authorize";
private static final String TOKEN_ENDPOINT = "https://www.strava.com/oauth/token";
public String getLocation() throws IOException {
Map<String, String> queryParameters = new HashMap<>();
queryParameters.put("client_id", client_id);
queryParameters.put("response_type", response_type);
queryParameters.put("redirect_uri", redirect_uri);
queryParameters.put("scope", scope);
return buildUrl(AUTHORIZATION_ENDPOINT, queryParameters);
}
public String getToken(String code) throws URISyntaxException {
Account account = accountService.getCurrentUser();
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
parameters.add("code", code);
parameters.add("client_id", client_id);
parameters.add("client_secret", client_secret);
parameters.add("grant_type", grant_type);
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(parameters, headers);
URI uri = new URI(TOKEN_ENDPOINT);
ResponseEntity<StravaTokenDetails> response = restTemplate.exchange(uri, HttpMethod.POST, request, StravaTokenDetails.class);
StravaTokenDetails stravaTokenDetails = response.getBody();
stravaTokenRepository.save(StravaToken.builder()
.accessToken(stravaTokenDetails.getAccessToken())
.refreshToken(stravaTokenDetails.getRefreshToken())
.expiresAt(stravaTokenDetails.getExpiresAt())
.account(account)
.build());
return mobileRedirectUri;
}
// Helper method to build a URL with query parameters
private String buildUrl (String endpoint, Map < String, String > queryParameters) throws IOException {
StringBuilder queryBuilder = new StringBuilder();
for (Map.Entry<String, String> entry : queryParameters.entrySet()) {
if (queryBuilder.length() > 0) {
queryBuilder.append("&");
}
queryBuilder.append(URLEncoder.encode(entry.getKey(), "UTF-8"));
queryBuilder.append("=");
queryBuilder.append(URLEncoder.encode(entry.getValue(), "UTF-8"));
}
return endpoint + "?" + queryBuilder.toString();
}
}
@Transactional(readOnly = true)
public Account getCurrentUser() {
String username = SecurityContextHolder.getContext().getAuthentication().getName();
return accountRepository.findAccountByEmailIgnoreCase(username).orElseThrow(EntityNotFoundException::new);
}
Источник: Stack Overflow на русском