You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot 3.2.1集成GitHub OAuth2后如何检查用户所属组织/团队

实现Spring Boot GitHub OAuth2登录后的组织/团队权限校验

核心步骤

1. 配置GitHub OAuth2 Scope

要访问用户的组织和团队信息,必须在OAuth2客户端配置中添加read:org权限,否则GitHub API会返回权限不足的错误。在application.yml中配置:

spring:
  security:
    oauth2:
      client:
        registration:
          github:
            client-id: YOUR_CLIENT_ID
            client-secret: YOUR_CLIENT_SECRET
            scope: read:user, read:org  # 新增read:org权限

2. 自定义OAuth2UserService扩展用户信息

Spring Security的OAuth2UserService负责处理登录后的用户信息,我们可以重写它来调用GitHub API获取组织和团队:

import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.web.client.RestTemplate;
import java.util.List;
import java.util.Map;

public class GitHubOAuth2UserService extends DefaultOAuth2UserService {
    private final RestTemplate restTemplate = new RestTemplate();

    @Override
    public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
        OAuth2User oAuth2User = super.loadUser(userRequest);
        String accessToken = userRequest.getAccessToken().getTokenValue();

        // 调用GitHub API获取用户所属组织
        List<Map<String, Object>> orgs = restTemplate.getForObject(
                "https://api.github.com/user/orgs?access_token=" + accessToken,
                List.class
        );
        // 调用GitHub API获取用户所属团队
        List<Map<String, Object>> teams = restTemplate.getForObject(
                "https://api.github.com/user/teams?access_token=" + accessToken,
                List.class
        );

        // 将组织和团队信息加入用户属性,方便后续权限校验
        oAuth2User.getAttributes().put("orgs", orgs);
        oAuth2User.getAttributes().put("teams", teams);

        return oAuth2User;
    }
}

3. 配置Spring Security使用自定义UserService

在Security配置类中,替换默认的OAuth2UserService:

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.web.SecurityFilterChain;

@Configuration
public class SecurityConfig {
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .authorizeHttpRequests(auth -> auth
                        .anyRequest().authenticated()
                )
                .oauth2Login(oauth2 -> oauth2
                        .userInfoEndpoint(userInfo -> userInfo
                                .userService(new GitHubOAuth2UserService())
                        )
                );
        return http.build();
    }
}

4. 实现权限校验

方法级权限校验

可以通过@PreAuthorize注解结合SpEL表达式,检查用户是否属于指定组织/团队:

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.core.user.OAuth2User;

@RestController
public class ResourceController {
    @GetMapping("/admin")
    @PreAuthorize("#oauth2User.attributes['orgs'].stream().anyMatch(org -> org['login'] == 'your-target-org')")
    public String adminResource(@AuthenticationPrincipal OAuth2User oauth2User) {
        return "Admin Access Granted";
    }

    @GetMapping("/team-member")
    @PreAuthorize("#oauth2User.attributes['teams'].stream().anyMatch(team -> team['name'] == 'your-target-team')")
    public String teamResource(@AuthenticationPrincipal OAuth2User oauth2User) {
        return "Team Member Access Granted";
    }
}

全局权限拦截(可选)

如果需要全局拦截特定路径,可以自定义Filter,检查用户的组织/团队信息:

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
import java.util.List;
import java.util.Map;

public class GitHubOrgTeamFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        if (auth != null && auth.getPrincipal() instanceof OAuth2User oauth2User) {
            List<Map<String, Object>> orgs = (List<Map<String, Object>>) oauth2User.getAttributes().get("orgs");
            boolean isInTargetOrg = orgs.stream().anyMatch(org -> "your-target-org".equals(org.get("login")));
            if (!isInTargetOrg && request.getRequestURI().startsWith("/admin")) {
                response.sendError(HttpServletResponse.SC_FORBIDDEN, "Not authorized to access this resource");
                return;
            }
        }
        filterChain.doFilter(request, response);
    }
}

然后在Security配置中添加这个Filter:

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
            .addFilterBefore(new GitHubOrgTeamFilter(), UsernamePasswordAuthenticationFilter.class)
            // 其他原有配置...
    return http.build();
}

注意事项

  • API速率限制:GitHub API有速率限制,登录时调用两次API(组织+团队)在免费额度内完全够用,无需额外处理。
  • 权限异常处理:如果用户授权时未同意read:org权限,API调用会返回403,此时可以在自定义UserService中捕获异常,引导用户重新授权。
  • 自定义UserDetails(可选):如果需要更灵活的权限管理,可以创建自定义UserDetails类,将组织/团队信息封装为GrantedAuthority,方便直接使用hasAuthority注解。

内容的提问来源于stack exchange,提问作者Luiggi33

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 08:05:36