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

基于JWT的Spring Boot资源权限控制:仅ROLE_ADMIN可创建锦标赛

Got it, let's get this sorted out for you. To restrict tournament creation exclusively to users with the ROLE_ADMIN role in your Spring Boot app, we'll need to tie together your User entity, Spring Security setup, and targeted permission checks. Here's a step-by-step breakdown tailored to your code:

1. Fix & Complete Your User Entity's Role Mapping

Your provided User entity code cuts off mid-@ManyToMany mapping—first, we need to finish that and make the class implement Spring Security's UserDetails interface so Security can recognize and validate user permissions.

Here's the updated User entity snippet:

@Entity
public class User implements UserDetails {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    public long id;
    private String username;
    @Length(min = 2, max = 60)
    private String password;
    private String email;
    private Long tsRegistration;
    private Long tslLastLogin;
    private Long bonusCredit;
    private boolean enabled;

    // Complete the ManyToMany role association
    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(
        name = "user_roles", // Note: Your original table name "user_intournament" seems off—this is a more standard name for user-role mappings
        joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"),
        inverseJoinColumns = @JoinColumn(name = "role_id", referencedColumnName = "id")
    )
    private Set<Role> roles;

    // Implement required UserDetails methods to expose permissions
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return roles.stream()
            .map(role -> new SimpleGrantedAuthority(role.getName()))
            .collect(Collectors.toList());
    }

    @Override
    public String getPassword() {
        return password;
    }

    @Override
    public String getUsername() {
        return username;
    }

    @Override
    public boolean isAccountNonExpired() {
        return true; // Adjust based on your app's account policies
    }

    @Override
    public boolean isAccountNonLocked() {
        return true; // Adjust based on your app's account policies
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true; // Adjust based on your app's account policies
    }

    @Override
    public boolean isEnabled() {
        return enabled;
    }

    // Add getters, setters, and constructors for all fields
}

You'll also need a simple Role entity to pair with this:

@Entity
public class Role {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;
    private String name; // Store roles as "ROLE_ADMIN" (Spring Security expects the ROLE_ prefix by default for hasRole() checks)

    // Add getters, setters, and constructors
}
2. Configure Spring Security to Enforce Route-Level Permissions

Next, set up a Security configuration class to define which endpoints require admin access. Assuming your tournament creation endpoint is a POST request to /api/tournaments, here's how to lock it down:

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                // Allow public access to open endpoints (adjust as needed)
                .requestMatchers("/api/public/**").permitAll()
                // Restrict tournament creation exclusively to ADMIN users
                .requestMatchers(HttpMethod.POST, "/api/tournaments").hasRole("ADMIN")
                // Require authentication for all other endpoints
                .anyRequest().authenticated()
            )
            // Use your preferred auth method (form login, JWT, OAuth2, etc.)
            .formLogin(form -> form.permitAll())
            .logout(logout -> logout.permitAll());

        return http.build();
    }

    // Always use a strong password encoder—never store plaintext passwords
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    // Wire up your user fetch logic (replace with your actual user repository call)
    @Bean
    public UserDetailsService userDetailsService(UserRepository userRepo) {
        return username -> userRepo.findByUsername(username)
            .orElseThrow(() -> new UsernameNotFoundException("User not found: " + username));
    }
}
3. Optional: Granular Method-Level Security

If you want to lock down specific service or controller methods directly (instead of just routes), enable method-level security and use the @PreAuthorize annotation:

First, add @EnableMethodSecurity to your SecurityConfig:

@Configuration
@EnableWebSecurity
@EnableMethodSecurity(prePostEnabled = true)
public class SecurityConfig {
    // ... existing configuration code ...
}

Then annotate your tournament creation method (in Controller or Service):

@RestController
@RequestMapping("/api/tournaments")
public class TournamentController {

    private final TournamentService tournamentService;

    // Constructor injection (preferred over @Autowired)
    public TournamentController(TournamentService tournamentService) {
        this.tournamentService = tournamentService;
    }

    // Only users with ROLE_ADMIN can execute this method
    @PreAuthorize("hasRole('ADMIN')")
    @PostMapping
    public ResponseEntity<Tournament> createTournament(@RequestBody Tournament tournament) {
        Tournament createdTourney = tournamentService.save(tournament);
        return ResponseEntity.status(HttpStatus.CREATED).body(createdTourney);
    }

    // Example: Allow any authenticated user to view tournaments
    @GetMapping
    public List<Tournament> getAllTournaments() {
        return tournamentService.findAll();
    }
}
Quick Reminders
  • Ensure your admin user's Role entity has a name value of ROLE_ADMIN (Spring Security's hasRole() automatically looks for the ROLE_ prefix—if you store roles without the prefix, use hasAuthority('ADMIN') instead).
  • Never skip password encoding—BCrypt is industry standard for this.
  • Adjust the auth method (form login, JWT, etc.) to match your app's requirements.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 09:18:33