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

Spring Boot OAuth登录后角色权限配置异常求助

问题排查

  1. 核心问题:CustomOAuth2User.getUserRoles()尝试从GitHub OAuth返回的用户属性中读取roles字段,但GitHub的OAuth用户信息接口不会返回该字段,导致roles始终为空集合,触发默认逻辑返回ROLE_USER。
  2. 次要问题:AuthService.loadUserByUsername()错误地将用户状态设置为accountExpired(true)、accountLocked(true)等,导致用户即使认证成功也会被判定为无效。

解决方案

1. 修改CustomOAuth2UserService,从数据库加载用户角色

注入UserRepository,在加载OAuth用户时查询数据库对应的用户记录,将角色传递给CustomOAuth2User:

@Service
public class CustomOAuth2UserService extends DefaultOAuth2UserService {

    private final UserRepository userRepository;

    public CustomOAuth2UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Override
    public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
        OAuth2User oauth2User = super.loadUser(userRequest);
        String githubId = oauth2User.getAttribute("id").toString();
        
        // 查询数据库中的用户角色
        Set<Role> userRoles = userRepository.findByIdentifier(githubId)
                .map(user -> Set.of(user.getRole()))
                .orElse(Collections.emptySet());
        
        return new CustomOAuth2User(oauth2User, userRoles);
    }
}

2. 修改CustomOAuth2User,接收并使用数据库中的角色

添加角色字段,修改构造方法和getUserRoles()方法:

public class CustomOAuth2User implements OAuth2User {

    private OAuth2User oauth2User;
    private Set<Role> roles; // 新增字段存储数据库中的角色

    public CustomOAuth2User(OAuth2User oauth2User, Set<Role> roles) {
        this.oauth2User = oauth2User;
        this.roles = roles;
    }

    @Override
    public Map<String, Object> getAttributes() {
        return oauth2User.getAttributes();
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        System.out.println("User roles:");
        for (Role role : roles) {
            System.out.println(role.name());
        }

        if (!roles.isEmpty()) {
            return roles.stream()
                    .map(role -> new SimpleGrantedAuthority("ROLE_" + role.name()))
                    .collect(Collectors.toList());
        } else {
            return Collections.singleton(new SimpleGrantedAuthority("ROLE_USER"));
        }
    }

    @Override
    public String getName() {
        return oauth2User.getAttribute("name");
    }

    private Set<Role> getUserRoles() {
        return this.roles; // 直接返回数据库中加载的角色
    }

    public String getEmail() {
        return oauth2User.<String>getAttribute("email");
    }
}

3. 修复AuthService中的用户状态错误

将用户状态全部改为false,确保用户有效:

@Service
public class AuthService implements UserDetailsService{

    private final UserRepository userRepository;

    public AuthService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Override
    public UserDetails loadUserByUsername(String identifier) throws UsernameNotFoundException {
        User user = userRepository.findByIdentifier(identifier)
                .orElseThrow(() -> new UsernameNotFoundException("User not found with GitHub user ID: " + identifier));

        return org.springframework.security.core.userdetails.User
                .withUsername(String.valueOf(user.getIdentifier()))
                .password(user.getPassword())
                .authorities(user.getAuthorities())
                .accountExpired(false) // 改为false
                .accountLocked(false) // 改为false
                .credentialsExpired(false) // 改为false
                .disabled(false) // 改为false
                .build();
    }
}

4. 可选优化:调整用户创建逻辑到CustomOAuth2UserService

确保加载用户时数据库已有记录,避免第一次登录时角色为空:

@Service
public class CustomOAuth2UserService extends DefaultOAuth2UserService {

    private final UserRepository userRepository;
    private final UserService userService;

    public CustomOAuth2UserService(UserRepository userRepository, UserService userService) {
        this.userRepository = userRepository;
        this.userService = userService;
    }

    @Override
    public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
        OAuth2User oauth2User = super.loadUser(userRequest);
        String githubId = oauth2User.getAttribute("id").toString();
        
        // 检查用户是否存在,不存在则创建
        User user = userRepository.findByIdentifier(githubId)
                .orElseGet(() -> {
                    UserDTO userDTO = new UserDTO(
                            oauth2User.getName(),
                            "username",
                            githubId,
                            oauth2User.getAttribute("avatar_url").toString(),
                            Role.ADMIN
                    );
                    return userService.create(userDTO);
                });
        
        Set<Role> userRoles = Set.of(user.getRole());
        return new CustomOAuth2User(oauth2User, userRoles);
    }
}

同时简化SecurityConfig的successHandler:

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    private final CustomOAuth2UserService oauthUserService;

    public SecurityConfig(CustomOAuth2UserService oauthUserService) {
        this.oauthUserService = oauthUserService;
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        return http
                .authorizeHttpRequests(auth -> {
                    auth.requestMatchers(HttpMethod.GET, "/userinfo").hasRole("ADMIN");
                    auth.requestMatchers(HttpMethod.GET, "/").hasRole("USER");
                    auth.anyRequest().authenticated();
                })
                .oauth2Login(oauth2 -> oauth2
                        .userInfoEndpoint(userInfo -> userInfo.userService(oauthUserService))
                        .successHandler((request, response, authentication) -> {
                            response.sendRedirect("/");
                        })
                )
                .build();
    }
}

验证逻辑

  • 第一次登录时,系统自动创建ADMIN角色的用户,CustomOAuth2User加载到该角色,返回ROLE_ADMIN权限,可访问/userinfo路由。
  • 后续登录直接从数据库读取角色,权限正确生效。
  • 普通用户(ROLE_USER)无法访问/userinfo,仅能访问/路由。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 13:24:59