Spring Security OAuth2 大揭秘
一、OAuth2是什么?為什么需要它?
OAuth2 是一個授權框架, 允許用戶授權第三方應用訪問他們的資源(比如 GitHub 上的個人信息), 而無需直接提供密碼。
例如: 你想用 GitHub 賬號登錄某個網站, 這個網站會跳轉到 GitHub 讓你授權, 授權成功后, 網站就能獲取你的 GitHub 基本信息(比如用戶名、頭像), 但不會拿到你的密碼.
OAuth2核心角色:
- 資源所有者(Resource Owner): 就是用戶本人
- 客戶端(Client): 我們的Spring Boot應用
- 授權服務器(Authorization Server): 比如GitHub、Google的OAuth2服務
- 資源服務器(Resource Server): 存儲用戶數據的服務器
OAuth2的核心實現流程圖:
圖片
二、Spring Security OAuth2快速入門
1) 添加依賴
首先, 在你的 pom.xml
里加入 Spring Security OAuth2 的依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
2) 配置application.yml
spring:
security:
oauth2:
client:
registration:
github:
client-id: your-github-client-id
client-secret: your-github-client-secret
scope: user:email,read:user
1. client-id
和 client-secret:
去 GitHub Developer Settings 申請 OAuth App 獲取.
2. scope:
定義你要獲取的用戶權限, 比如 user:email
可以獲取用戶的郵箱.
3) 創建Security配置類
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/login**").permitAll()
.anyRequest().authenticated()
.and()
.oauth2Login(); // 啟用 OAuth2 登錄
}
}
現在, 訪問你的網站, 點擊登錄, 就會自動跳轉到 GitHub 授權頁面了.
三、自定義OAuth2用戶信息
默認情況下, Spring Security 只會返回基本的用戶信息(如 name
, email).
但如果你想獲取更多信息(比如 GitHub 的 bio
、location)
,就需要自定義 OAuth2UserService.
@Service
public class CustomOAuth2UserService implements OAuth2UserService<OAuth2UserRequest, OAuth2User> {
private final OAuth2UserService<OAuth2UserRequest, OAuth2User> defaultService = new DefaultOAuth2UserService();
@Override
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
// 1. 先讓默認的 Service 加載用戶信息
OAuth2User user = defaultService.loadUser(userRequest);
// 2. 獲取額外的用戶信息(GitHub API)
if ("github".equals(userRequest.getClientRegistration().getRegistrationId())) {
String accessToken = userRequest.getAccessToken().getTokenValue();
Map<String, Object> extraAttributes = fetchGitHubUserDetails(accessToken);
user = new DefaultOAuth2User(user.getAuthorities(), extraAttributes, "login"); // "login" 是 GitHub 的主鍵字段
}
return user;
}
private Map<String, Object> fetchGitHubUserDetails(String accessToken) {
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setBearerAuth(accessToken);
HttpEntity<String> entity = new HttpEntity<>(headers);
ResponseEntity<Map> response = restTemplate.exchange(
"https://api.github.com/user",
HttpMethod.GET,
entity,
Map.class
);
return response.getBody();
}
}
更新Security配置:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomOAuth2UserService customOAuth2UserService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/login**").permitAll()
.anyRequest().authenticated()
.and()
.oauth2Login()
.userInfoEndpoint()
.userService(customOAuth2UserService); // 使用自定義的 UserService
}
}
四、獲取登錄用戶信息
1) 通過SecurityContextHolder獲取:
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.core.user.OAuth2User;
@GetMapping("/user")
public String getUserInfo() {
OAuth2User principal = (OAuth2User) SecurityContextHolder.getContext()
.getAuthentication()
.getPrincipal();
return "User: " + principal.getAttributes();
}
2) 通過@AuthenticationPrincipal注解獲取:
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.core.user.OAuth2User;
@GetMapping("/user")
public String getUserInfo(@AuthenticationPrincipal OAuth2User principal) {
// GitHub返回的屬性示例
String name = principal.getAttribute("login"); // GitHub用戶名
String email = principal.getAttribute("email");
String avatar = principal.getAttribute("avatar_url");
return "Hello, " + name + "! Email: " + email;
}