集成 OAuth2 可以实现第三方登录和 API 访问授权。OAuth2 是一个开放标准,允许用户授权第三方应用访问他们的资源,而无需共享用户的凭据。以下是使用 Spring Security 实现 OAuth2 的基本步骤:

  1. 添加依赖:

    在项目的 pom.xml 文件中添加 Spring Security OAuth2 相关的依赖:

    
      

    xmlCopy code

    <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-oauth2-client</artifactId> </dependency>

  2. 配置 OAuth2:

    创建一个配置类,配置 OAuth2 相关的信息。以下是一个简单的示例:

    
      

    javaCopy code

    import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; import org.springframework.security.oauth2.core.AuthorizationGrantType; import org.springframework.security.oauth2.core.ClientAuthenticationMethod; @Configuration public class OAuth2Config { @Bean public UserDetailsService userDetailsService() { return (username) -> { UserDetails userDetails = User .withUsername(username) .password(passwordEncoder().encode("password")) // Replace with actual password .authorities(AuthorityUtils.createAuthorityList("ROLE_USER")) .build(); return userDetails; }; } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean public ClientRegistrationRepository clientRegistrationRepository() { return (new InMemoryClientRegistrationRepository(githubClientRegistration())); } private ClientRegistration githubClientRegistration() { return ClientRegistration .withRegistrationId("github") .clientId("your-github-client-id") .clientSecret("your-github-client-secret") .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE) .clientAuthenticationMethod(ClientAuthenticationMethod.BASIC) .redirectUri("{baseUrl}/login/oauth2/code/{registrationId}") .scope("read:user") .authorizationUri("https://github.com/login/oauth/authorize") .tokenUri("https://github.com/login/oauth/access_token") .userInfoUri("https://api.github.com/user") .userNameAttributeName("id") .clientName("GitHub") .build(); } }

    请替换上述代码中的占位符(如 your-github-client-idyour-github-client-secret)为实际的 GitHub 应用程序信息。

  3. 配置 Spring Security:

    在 Spring Security 的配置类中,启用 OAuth2 登录:

    
      

    javaCopy code

    import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter; import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint; @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private OAuth2AuthorizationRequestRedirectFilter oAuth2AuthorizationRequestRedirectFilter; @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/", "/login**", "/error**").permitAll() .anyRequest().authenticated() .and() .oauth2Login() .loginPage("/login") .defaultSuccessURL("/home") .failureUrl("/login?error=true") .and() .exceptionHandling() .authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login")) .and() .addFilterBefore(oAuth2AuthorizationRequestRedirectFilter, CsrfFilter.class); } @Bean public OAuth2AuthorizationRequestRedirectFilter oAuth2AuthorizationRequestRedirectFilter() { return new OAuth2AuthorizationRequestRedirectFilter(clientRegistrationRepository(), "/login/oauth2/code/*"); } }

  4. 创建登录和首页页面:

    创建一个登录页面和一个首页页面,用于演示登录和登录成功后的页面。

    • src/main/resources/templates/login.html:

      
          

      htmlCopy code

      <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Login</title> </head> <body> <h2>Login</h2> <p><a href="/login/oauth2/authorization/github">Login with GitHub</a></p> </body> </html>

    • src/main/resources/templates/home.html:

      
          

      htmlCopy code

      <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Home</title> </head> <body> <h2>Home</h2> <p>Welcome! You are now authenticated.</p> </body> </html>

  5. 启动应用程序:

    启动你的 Spring Boot 应用程序,并访问 http://localhost:8080/login 查看登录页面。点击 "Login with GitHub" 将跳转到 GitHub 登录页面,登录成功后将重定向到应用程序的首页。

以上是一个简单的使用 Spring Security 实现 OAuth2 的示例。实际应用中,你可能需要根据实际需求配置更多的信息,如多个第三方登录提供商、授权范围的配置等。详细的配置可以参考 Spring Security 和各个 OAuth2 提供商的文档

  1. 获取用户信息:

    当用户通过 OAuth2 登录成功后,你可能需要获取用户的详细信息。你可以通过注入 OAuth2UserService 来实现:

    
      

    javaCopy code

    import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService; import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService; import org.springframework.security.oauth2.client.userinfo.OAuth2UserService; import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.security.oauth2.core.user.OAuth2UserAuthority; @Configuration public class OAuth2Config { @Autowired private OAuth2AuthorizedClientService authorizedClientService; // existing methods... @Bean public OAuth2UserService<OAuth2UserRequest, OAuth2User> oAuth2UserService(ClientRegistrationRepository clientRegistrationRepository) { DefaultOAuth2UserService delegate = new DefaultOAuth2UserService(); return new CustomOAuth2UserService(delegate, authorizedClientService); } }

    创建一个自定义的 CustomOAuth2UserService 类,继承自 DefaultOAuth2UserService,用于获取用户信息:

    
      

    javaCopy code

    import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService; import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest; import org.springframework.security.oauth2.client.userinfo.OAuth2UserResponse; import org.springframework.security.oauth2.core.OAuth2AccessToken; import org.springframework.security.oauth2.core.OAuth2AuthenticationException; import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.security.oauth2.core.user.OAuth2UserAuthority; import org.springframework.security.oauth2.core.user.OAuth2UserRequest; import org.springframework.security.oauth2.core.user.OAuth2UserResponse; import org.springframework.security.oauth2.core.user.OAuth2UserResponseException; public class CustomOAuth2UserService extends DefaultOAuth2UserService { // existing methods... @Override public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException { OAuth2User user = super.loadUser(userRequest); try { return new CustomOAuth2User(user, authorizedClientService.loadAuthorizedClient( userRequest.getClientRegistration().getRegistrationId(), userRequest.getPrincipalName())); } catch (OAuth2UserResponseException e) { throw new OAuth2AuthenticationException(e.getError(), e); } } }

    CustomOAuth2User 类中,你可以获取并处理用户的详细信息,例如:

    
      

    javaCopy code

    import org.springframework.security.core.GrantedAuthority; import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest; import org.springframework.security.oauth2.core.OAuth2AccessToken; import org.springframework.security.oauth2.core.OAuth2AuthenticationException; import org.springframework.security.oauth2.core.user.DefaultOAuth2User; import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.security.oauth2.core.user.OAuth2UserAuthority; import java.util.Collection; import java.util.Map; public class CustomOAuth2User extends DefaultOAuth2User { private final OAuth2AuthorizedClient authorizedClient; public CustomOAuth2User(OAuth2User user, OAuth2AuthorizedClient authorizedClient) { super(user.getAuthorities(), user.getAttributes(), "id"); this.authorizedClient = authorizedClient; } // Additional methods to get and process user details... }

    在这里,你可以自定义 CustomOAuth2User 类来获取和处理用户的详细信息,包括用户 ID、用户名、电子邮件等。

  2. 注销:

    考虑用户注销时,你可能需要注销用户的 OAuth2 授权。可以配置注销端点来实现:

    
      

    javaCopy code

    import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService; import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService; import org.springframework.security.oauth2.client.userinfo.OAuth2UserService; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client; @Configuration @EnableOAuth2Client public class OAuth2Config { @Autowired private OAuth2AuthorizedClientService authorizedClientService; // existing methods... @Bean public OAuth2UserService<OAuth2UserRequest, OAuth2User> oAuth2UserService(ClientRegistrationRepository clientRegistrationRepository) { DefaultOAuth2UserService delegate = new DefaultOAuth2UserService(); return new CustomOAuth2UserService(delegate, authorizedClientService); } @Bean public ClientRegistrationRepository clientRegistrationRepository() { // existing method... } @Bean public OAuth2AuthorizationRequestRedirectFilter oAuth2AuthorizationRequestRedirectFilter() { // existing method... } }

    在上述配置中,EnableOAuth2Client 注解启用了 OAuth2 客户端支持。在用户注销时,可以使用以下代码来注销 OAuth2 授权:

    
      

    javaCopy code

    import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.Authentication; import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import javax.servlet.http.HttpServletRequest; @Controller @RequestMapping("/logout") public class LogoutController { @Autowired private OAuth2AuthorizedClientService authorizedClientService; @GetMapping public String logout(HttpServletRequest request, Authentication authentication) { if (authentication != null) { OAuth2AuthorizedClient authorizedClient = authorizedClientService.loadAuthorizedClient( "github", authentication.getName()); if (authorizedClient != null) { authorizedClientService.removeAuthorizedClient( "github", authentication.getName()); } } return "redirect:/login?logout"; } }

    上述代码在用户注销时移除了 GitHub 的 OAuth2 授权。

  3. API 访问授权:

    如果你希望在应用程序中访问第三方 API,你可以使用 RestTemplateWebClient 来添加 OAuth2 授权头。以下是一个使用 WebClient 的简单示例:

    
      

    javaCopy code

    import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.Authentication; import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService; import org.springframework.stereotype.Service; import org.springframework.web.reactive.function.client.WebClient; @Service public class GitHubApiService { private final WebClient webClient; private final OAuth2AuthorizedClientService authorizedClientService; @Autowired public GitHubApiService(WebClient.Builder webClientBuilder, OAuth2AuthorizedClientService authorizedClientService) { this.webClient = webClientBuilder.baseUrl("https://api.github.com").build(); this.authorizedClientService = authorizedClientService; } public String getUserInfo(Authentication authentication) { OAuth2AuthorizedClient authorizedClient = authorizedClientService.loadAuthorizedClient( "github", authentication.getName()); return webClient .get() .uri("/user") .headers(headers -> headers.setBearerAuth(authorizedClient.getAccessToken().getTokenValue())) .retrieve() .bodyToMono(String.class) .block(); } }

    上述代码使用 WebClient 向 GitHub API 发送请求,并添加了 OAuth2 授权头。

这是一个简单的 OAuth2 集成示例,你可以根据实际需求和业务逻辑进一步定制和扩展。在开发过程中,请参考 Spring Security 和 OAuth2 文档,以确保正确实现所需的功能和安全性。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐