mirror of
https://github.com/nagisa77/OpenIsle.git
synced 2026-04-21 19:37:29 +08:00
feat: update X OAuth
This commit is contained in:
@@ -8,6 +8,7 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.http.*;
|
import org.springframework.http.*;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.web.client.HttpClientErrorException;
|
||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
import org.springframework.util.MultiValueMap;
|
import org.springframework.util.MultiValueMap;
|
||||||
import org.springframework.util.LinkedMultiValueMap;
|
import org.springframework.util.LinkedMultiValueMap;
|
||||||
@@ -23,49 +24,64 @@ public class TwitterAuthService {
|
|||||||
@Value("${twitter.client-id:}")
|
@Value("${twitter.client-id:}")
|
||||||
private String clientId;
|
private String clientId;
|
||||||
|
|
||||||
public Optional<User> authenticate(String code, String codeVerifier, com.openisle.model.RegisterMode mode, String redirectUri) {
|
public Optional<User> authenticate(
|
||||||
|
String code,
|
||||||
|
String codeVerifier,
|
||||||
|
RegisterMode mode,
|
||||||
|
String redirectUri) {
|
||||||
|
|
||||||
|
// 1. 交换 token
|
||||||
|
String tokenUrl = "https://api.twitter.com/2/oauth2/token";
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||||
|
headers.setAccept(List.of(MediaType.APPLICATION_JSON));
|
||||||
|
|
||||||
|
// Twitter PKCE 要求的五个参数
|
||||||
|
MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
|
||||||
|
body.add("client_id", clientId);
|
||||||
|
body.add("grant_type", "authorization_code");
|
||||||
|
body.add("code", code);
|
||||||
|
body.add("code_verifier", codeVerifier);
|
||||||
|
body.add("redirect_uri", redirectUri); // 一律必填
|
||||||
|
// 如果你的 app 属于机密客户端,必须带 client_secret
|
||||||
|
// body.add("client_secret", clientSecret);
|
||||||
|
|
||||||
|
ResponseEntity<JsonNode> tokenRes;
|
||||||
try {
|
try {
|
||||||
String tokenUrl = "https://api.twitter.com/2/oauth2/token";
|
tokenRes = restTemplate.postForEntity(tokenUrl, new HttpEntity<>(body, headers), JsonNode.class);
|
||||||
HttpHeaders headers = new HttpHeaders();
|
} catch (HttpClientErrorException e) {
|
||||||
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
|
||||||
|
|
||||||
MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
|
|
||||||
body.add("client_id", clientId);
|
|
||||||
body.add("code", code);
|
|
||||||
body.add("grant_type", "authorization_code");
|
|
||||||
body.add("code_verifier", codeVerifier);
|
|
||||||
if (redirectUri != null) {
|
|
||||||
body.add("redirect_uri", redirectUri);
|
|
||||||
}
|
|
||||||
|
|
||||||
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(body, headers);
|
|
||||||
ResponseEntity<JsonNode> tokenRes = restTemplate.postForEntity(tokenUrl, request, JsonNode.class);
|
|
||||||
if (!tokenRes.getStatusCode().is2xxSuccessful() || tokenRes.getBody() == null || !tokenRes.getBody().has("access_token")) {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
String accessToken = tokenRes.getBody().get("access_token").asText();
|
|
||||||
|
|
||||||
HttpHeaders authHeaders = new HttpHeaders();
|
|
||||||
authHeaders.setBearerAuth(accessToken);
|
|
||||||
HttpEntity<Void> entity = new HttpEntity<>(authHeaders);
|
|
||||||
ResponseEntity<JsonNode> userRes = restTemplate.exchange(
|
|
||||||
"https://api.twitter.com/2/users/me", HttpMethod.GET, entity, JsonNode.class);
|
|
||||||
if (!userRes.getStatusCode().is2xxSuccessful() || userRes.getBody() == null) {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
JsonNode userNode = userRes.getBody();
|
|
||||||
String username = userNode.hasNonNull("username") ? userNode.get("username").asText() : null;
|
|
||||||
String email = null;
|
|
||||||
if (userNode.hasNonNull("email")) {
|
|
||||||
email = userNode.get("email").asText();
|
|
||||||
}
|
|
||||||
if (email == null) {
|
|
||||||
email = username + "@twitter.com";
|
|
||||||
}
|
|
||||||
return Optional.of(processUser(email, username, mode));
|
|
||||||
} catch (Exception e) {
|
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JsonNode tokenJson = tokenRes.getBody();
|
||||||
|
if (tokenJson == null || !tokenJson.hasNonNull("access_token")) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
String accessToken = tokenJson.get("access_token").asText();
|
||||||
|
|
||||||
|
// 2. 拉取用户信息
|
||||||
|
HttpHeaders authHeaders = new HttpHeaders();
|
||||||
|
authHeaders.setBearerAuth(accessToken);
|
||||||
|
ResponseEntity<JsonNode> userRes;
|
||||||
|
try {
|
||||||
|
userRes = restTemplate.exchange(
|
||||||
|
"https://api.twitter.com/2/users/me",
|
||||||
|
HttpMethod.GET,
|
||||||
|
new HttpEntity<>(authHeaders),
|
||||||
|
JsonNode.class);
|
||||||
|
} catch (HttpClientErrorException e) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonNode data = userRes.getBody() == null ? null : userRes.getBody().path("data");
|
||||||
|
String username = data != null ? data.path("username").asText(null) : null;
|
||||||
|
if (username == null) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Twitter v2 默认拿不到 email;如果你申请到 email.scope,可改用 /2/users/:id?user.fields=email
|
||||||
|
String email = username + "@twitter.com";
|
||||||
|
return Optional.of(processUser(email, username, mode));
|
||||||
}
|
}
|
||||||
|
|
||||||
private User processUser(String email, String username, com.openisle.model.RegisterMode mode) {
|
private User processUser(String email, String username, com.openisle.model.RegisterMode mode) {
|
||||||
|
|||||||
Reference in New Issue
Block a user