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

Spring Boot API认证咨询:角色权限控制与客户端对接问题

解决方案

一、用Spring Security实现Token认证与角色权限控制

1. 添加依赖

在pom.xml中引入核心依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- JWT相关依赖 -->
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
    <version>0.11.5</version>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-impl</artifactId>
    <version>0.11.5</version>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-jackson</artifactId>
    <version>0.11.5</version>
    <scope>runtime</scope>
</dependency>

2. 配置Security规则

创建SecurityConfig类,关闭默认表单登录,配置URL权限拦截,添加JWT过滤器:

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Autowired
    private JwtAuthenticationFilter jwtAuthFilter;

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .csrf(csrf -> csrf.disable())
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/api/public/**").permitAll() // 公共接口允许匿名访问
                .requestMatchers("/api/admin/**").hasRole("ADMIN") // admin接口需ADMIN角色
                .requestMatchers("/api/user/**").hasAnyRole("USER", "ADMIN") // user接口允许USER/ADMIN
                .anyRequest().authenticated()
            )
            .exceptionHandling(ex -> ex
                .authenticationEntryPoint((request, response, authException) -> {
                    response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "未授权:请携带有效Token");
                })
                .accessDeniedHandler((request, response, accessDeniedException) -> {
                    response.sendError(HttpServletResponse.SC_FORBIDDEN, "权限不足:无访问该接口的权限");
                })
            )
            .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class);

        return http.build();
    }

    // 配置用户认证管理器(示例:从数据库取用户,这里简化)
    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
        return config.getAuthenticationManager();
    }
}

3. 实现JWT过滤器

编写JwtAuthenticationFilter负责解析请求头中的Token,验证并注入用户信息:

@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    @Value("${jwt.secret}")
    private String jwtSecret;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String authHeader = request.getHeader("Authorization");
        String token = null;
        String username = null;

        // 提取Bearer Token
        if (authHeader != null && authHeader.startsWith("Bearer ")) {
            token = authHeader.substring(7);
            try {
                username = Jwts.parserBuilder()
                    .setSigningKey(Keys.hmacShaKeyFor(jwtSecret.getBytes()))
                    .build()
                    .parseClaimsJws(token)
                    .getBody()
                    .getSubject();
            } catch (JwtException e) {
                response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Token无效或已过期");
                return;
            }
        }

        // 验证用户并注入SecurityContext
        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
            // 这里可以从数据库查询用户角色,示例中硬编码角色
            List<GrantedAuthority> authorities = Arrays.asList(
                new SimpleGrantedAuthority("ROLE_USER"),
                new SimpleGrantedAuthority("ROLE_ADMIN") // 根据实际用户角色设置
            );
            Authentication auth = new UsernamePasswordAuthenticationToken(username, null, authorities);
            SecurityContextHolder.getContext().setAuthentication(auth);
        }

        filterChain.doFilter(request, response);
    }
}

4. 登录接口生成Token

创建登录接口,验证用户身份后返回JWT:

@RestController
@RequestMapping("/api/public")
public class AuthController {

    @Value("${jwt.secret}")
    private String jwtSecret;
    @Value("${jwt.expirationMs}")
    private long jwtExpirationMs;

    @PostMapping("/login")
    public ResponseEntity<String> login(@RequestBody LoginRequest request) {
        // 这里替换为实际的用户名密码验证逻辑
        if ("admin".equals(request.getUsername()) && "admin123".equals(request.getPassword())) {
            String token = Jwts.builder()
                .setSubject(request.getUsername())
                .setIssuedAt(new Date())
                .setExpiration(new Date(new Date().getTime() + jwtExpirationMs))
                .claim("roles", Arrays.asList("ROLE_ADMIN"))
                .signWith(Keys.hmacShaKeyFor(jwtSecret.getBytes()), SignatureAlgorithm.HS256)
                .compact();
            return ResponseEntity.ok(token);
        }
        return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("用户名或密码错误");
    }
}

// 登录请求DTO
class LoginRequest {
    private String username;
    private String password;
    // getter/setter
}

二、关于Auth0的疑问解答

  • Auth0支持多个API:在Auth0控制台的「APIs」菜单下可以创建多个API资源,每个API有独立的Audience标识,无需担心只能单API的问题。
  • 本地运行时的Audience设置:可以填你本地API的根路径(如http://localhost:8080/api),或者在Auth0创建API时自定义的Identifier值,两者保持一致即可。
  • Spring Boot集成Auth0:引入Auth0的spring-security-jwt依赖,配置auth0.domain和auth0.audience,然后用JwtWebSecurityConfigurer快速集成token验证,角色权限可以通过Auth0用户的「Roles」配置,token会自动包含roles声明,在Spring Security中用hasRole()即可校验。

三、测试网页客户端的认证方式

1. 基于自定义JWT的客户端实现

  • 做一个简单的登录页面,输入用户名密码后调用/api/public/login接口获取Token,将Token存储在localStorage中。
  • 后续调用API时,在请求头中添加Authorization: Bearer <token>,示例代码(原生JS):
// 登录获取Token
async function login() {
    const response = await fetch('/api/public/login', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ username: 'admin', password: 'admin123' })
    });
    const token = await response.text();
    localStorage.setItem('authToken', token);
}

// 调用需认证的API
async function callProtectedApi() {
    const token = localStorage.getItem('authToken');
    const response = await fetch('/api/admin/dashboard', {
        headers: { 'Authorization': `Bearer ${token}` }
    });
    const data = await response.json();
    console.log(data);
}

2. 基于Auth0的客户端实现

  • 使用Auth0提供的Lock组件或自定义登录UI,引导用户登录后获取Token,同样将Token存储在本地,后续请求添加Authorization头。
  • Auth0会自动处理Token的刷新、过期等逻辑,适合快速搭建测试客户端。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 12:05:30