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

如何基于Spring Boot与Keycloak编写简易登录与授权REST接口?

Spring Boot + Keycloak 实现基础登录与授权REST接口

1. 添加依赖

在pom.xml中引入必要依赖(Maven示例,Gradle可对应转换):

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>org.keycloak</groupId>
        <artifactId>keycloak-spring-boot-starter</artifactId>
        <version>22.0.5</version> <!-- 匹配你的Keycloak服务版本 -->
    </dependency>
</dependencies>

2. Keycloak 服务端前置配置

  • 创建Realm(如my-app-realm)
  • 新建客户端:Access Type设为confidential,Valid Redirect URIs填http://localhost:8080/*,记录客户端ID和密钥
  • 新建用户并分配角色(如USER、ADMIN)

3. Spring Boot 配置

在application.yml中添加Keycloak与Security配置:

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: http://localhost:8080/realms/my-app-realm # Keycloak Realm地址

keycloak:
  auth-server-url: http://localhost:8080 # Keycloak服务地址
  realm: my-app-realm
  resource: my-app-client # 客户端ID
  credentials:
    secret: your-client-secret # 客户端密钥
  use-resource-role-mappings: true

4. 实现登录接口(封装Keycloak令牌获取)

自己封装登录接口,内部调用Keycloak的/oauth2/token端点返回JWT令牌:

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

    @Value("${keycloak.auth-server-url}")
    private String authServerUrl;
    @Value("${keycloak.realm}")
    private String realm;
    @Value("${keycloak.resource}")
    private String clientId;
    @Value("${keycloak.credentials.secret}")
    private String clientSecret;

    @PostMapping("/login")
    public ResponseEntity<?> login(@RequestBody LoginRequest request) {
        // 构建Keycloak令牌请求参数
        MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
        params.add("grant_type", "password");
        params.add("username", request.getUsername());
        params.add("password", request.getPassword());
        params.add("client_id", clientId);
        params.add("client_secret", clientSecret);

        // 调用Keycloak令牌端点
        RestTemplate restTemplate = new RestTemplate();
        String tokenUrl = authServerUrl + "/realms/" + realm + "/protocol/openid-connect/token";
        try {
            ResponseEntity<TokenResponse> response = restTemplate.postForEntity(tokenUrl, params, TokenResponse.class);
            return ResponseEntity.ok(response.getBody());
        } catch (HttpClientErrorException e) {
            return ResponseEntity.status(e.getStatusCode()).body("登录失败:" + e.getResponseBodyAsString());
        }
    }

    // 辅助请求类
    public static class LoginRequest {
        private String username;
        private String password;
        // getter/setter
    }

    // 辅助响应类
    public static class TokenResponse {
        private String access_token;
        private String refresh_token;
        private long expires_in;
        // getter/setter
    }
}

5. 实现授权控制的REST接口

通过Spring Security注解或路径配置实现角色授权:

方式1:方法级注解

@RestController
@RequestMapping("/api/users")
public class UserController {

    // 仅USER角色可访问
    @GetMapping("/profile")
    @PreAuthorize("hasRole('USER')")
    public ResponseEntity<?> getProfile() {
        // 获取当前登录用户信息
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        return ResponseEntity.ok("当前用户:" + auth.getName() + ",角色:" + auth.getAuthorities());
    }

    // 仅ADMIN角色可访问
    @GetMapping("/list")
    @PreAuthorize("hasRole('ADMIN')")
    public ResponseEntity<?> getUserList() {
        return ResponseEntity.ok("管理员查看用户列表");
    }
}

方式2:全局路径配置(可选)

创建Security配置类,统一配置接口权限:

@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        super.configure(http);
        http.authorizeHttpRequests(auth -> auth
                .requestMatchers("/api/auth/**").permitAll() // 登录接口放行
                .requestMatchers("/api/users/list").hasRole("ADMIN")
                .anyRequest().authenticated()
        );
        // 禁用CSRF,适配REST接口
        http.csrf(csrf -> csrf.disable());
    }

    // 注册Keycloak认证提供者
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        KeycloakAuthenticationProvider keycloakAuthProvider = keycloakAuthenticationProvider();
        keycloakAuthProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
        auth.authenticationProvider(keycloakAuthProvider);
    }

    // 注册Keycloak过滤器(REST接口无需会话)
    @Bean
    @Override
    protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
        return new NullAuthenticatedSessionStrategy();
    }
}

测试说明

  1. 调用POST /api/auth/login,传入用户名密码,获取access_token
  2. 调用受保护接口时,在请求头添加Authorization: Bearer <access_token>
  3. 无令牌、令牌无效或无对应角色时,会返回401/403状态码

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 04:15:41