如何从 Discord OAUTH2 获取响应并将其转换为我自己的 UserDetails,我可以在整个代码中使用它
Posted
技术标签:
【中文标题】如何从 Discord OAUTH2 获取响应并将其转换为我自己的 UserDetails,我可以在整个代码中使用它【英文标题】:How do I take the response from Discord OAUTH2 and translate it in to my own UserDetails that I can use throughout my code 【发布时间】:2021-10-05 10:22:03 【问题描述】:我正在为我的应用程序使用 Spring Boot + Spring Security OAUTH 2。我想使用 Spring OAUTH2 来“使用 Discord 登录”,然后将 discord 在身份验证成功时提供的信息解析到我自己的实现 UserDetails
的 JPA 实体中。另外,我想实现我自己的 UserDetailsService
来返回我创建的自定义用户实体。
基本上,我只希望 Discord 提供有关用户的唯一信息,以便我可以根据响应构建自己的 Account
实体。
我已经阅读了以下文章,但我仍然不明白该怎么做:
https://www.baeldung.com/spring-security-oauth-principal-authorities-extractor
https://www.devglan.com/spring-security/spring-oauth2-role-based-authorization
另外,这是我的 OAuth2 设置:
安全配置(WebSecurityConfigurerAdapter
):
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter
@Autowired
private AuthSuccessHandler authSuccessHandler;
@Override
protected void configure(HttpSecurity http) throws Exception
http
.authorizeRequests()
.antMatchers(HttpMethod.GET, "/").permitAll()
.antMatchers(HttpMethod.GET, "/favicon.ico").permitAll()
.antMatchers(HttpMethod.GET, "/web/**").permitAll()
.antMatchers(HttpMethod.GET, "/oauth2/authorization/discord").anonymous()
.antMatchers(HttpMethod.GET, "/login").anonymous()
.antMatchers(HttpMethod.GET, "/logout").permitAll()
.and()
.logout()
.logoutSuccessUrl("/")
.and()
.oauth2Login()
.successHandler(authSuccessHandler)
.tokenEndpoint().accessTokenResponseClient(accessTokenResponseClient())
.and()
.userInfoEndpoint().userService(userService());
@Bean
public OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> accessTokenResponseClient()
DefaultAuthorizationCodeTokenResponseClient client = new DefaultAuthorizationCodeTokenResponseClient();
client.setRequestEntityConverter(new OAuth2AuthorizationCodeGrantRequestEntityConverter()
@Override
public RequestEntity<?> convert(OAuth2AuthorizationCodeGrantRequest oauth2Request)
return addUserAgentHeader(Objects.requireNonNull(super.convert(oauth2Request)));
);
return client;
@Bean
public OAuth2UserService<OAuth2UserRequest, OAuth2User> userService()
DefaultOAuth2UserService service = new DefaultOAuth2UserService();
service.setRequestEntityConverter(new OAuth2UserRequestEntityConverter()
@Override
public RequestEntity<?> convert(OAuth2UserRequest userRequest)
return addUserAgentHeader(
Objects.requireNonNull(super.convert(userRequest)));
);
return service;
private RequestEntity<?> addUserAgentHeader(RequestEntity<?> request)
HttpHeaders headers = new HttpHeaders();
headers.putAll(request.getHeaders());
headers.add(HttpHeaders.USER_AGENT, "Mozilla/5.0 (X11; Linux x86_64; rv:33.0) Gecko/20100101 Firefox/33.0");
return new RequestEntity<>(request.getBody(), headers, request.getMethod(), request.getUrl());
AuthSuccessHandler (AuthenticationSuccessHandler
)
正如您所看到的,我正在尝试通过根据 discord 提供的信息保存 JPA 实体并仅从数据库中提取而不是获取当前用户来解决此问题,这会阻止我使用角色和权限。
@Component
@RequiredArgsConstructor
@Slf4j
public class AuthSuccessHandler implements AuthenticationSuccessHandler
private final AccountRepository accountRepository;
private final RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authentication) throws IOException, ServletException
AuthenticationSuccessHandler.super.onAuthenticationSuccess(request, response, chain, authentication);
@Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException
OAuth2User oAuth2User = ((OAuth2AuthenticationToken) authentication).getPrincipal();
// oAuth2User.getAttributes().forEach((s, o) ->
// System.out.println(s + " : " + o);
// );
Long discordId = Long.parseLong(Objects.requireNonNull(oAuth2User.getAttribute("id")));
Optional<Account> accountOptional = accountRepository.findAccountByDiscordId(discordId);
if (!httpServletResponse.isCommitted())
if (accountOptional.isEmpty())
accountRepository.save(getAccountFromOAuth2User(oAuth2User));
redirectStrategy.sendRedirect(httpServletRequest, httpServletResponse, "/dashboard");
else
log.warn("Response committed");
private Account getAccountFromOAuth2User(OAuth2User oAuth2User)
return new Account(Long.parseLong(oAuth2User.getAttribute("id")),oAuth2User.getAttribute("username"), oAuth2User.getAttribute("discriminator"));
application.properties
spring.security.oauth2.client.registration.discord.client-name=Discord
spring.security.oauth2.client.registration.discord.client-id=**CLIENT**
spring.security.oauth2.client.registration.discord.client-secret=**SECRET**
spring.security.oauth2.client.registration.discord.clientAuthenticationMethod=post
spring.security.oauth2.client.registration.discord.authorizationGrantType=authorization_code
spring.security.oauth2.client.registration.discord.redirect-uri=http://localhost:8081/login/oauth2/code/discord
spring.security.oauth2.client.registration.discord.scope=identify
spring.security.oauth2.client.provider.discord.authorization-uri=https://discordapp.com/api/oauth2/authorize
spring.security.oauth2.client.provider.discord.token-uri=https://discordapp.com/api/oauth2/token
spring.security.oauth2.client.provider.discord.user-info-uri=https://discordapp.com/api/users/@me
spring.security.oauth2.client.provider.discord.user-name-attribute=username
对此的任何帮助将不胜感激。
提前致谢!
编辑: 使用的大部分代码来自这个 GitHub 存储库:
https://github.com/Samurus/spring-boot-discord-oauth-example
【问题讨论】:
【参考方案1】:我通过使用CustomUserTypesOAuth2UserService
解决了这个问题,这让我可以使用实现OAuth2User
的自定义类
【讨论】:
以上是关于如何从 Discord OAUTH2 获取响应并将其转换为我自己的 UserDetails,我可以在整个代码中使用它的主要内容,如果未能解决你的问题,请参考以下文章
如何从 api 获取 json 数据并将其以嵌入形式发送到 discord.py 中?
如何获取表单数据并将其发送到 discord webhook?
OAuth2:Discord API 总是以 "error": "invalid_grant" 响应
Discord 使用 url-query 中的“代码”发送 Oauth2 重定向 url。如何在我的谷歌脚本中获取该代码