如何基于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(); } }
测试说明
- 调用
POST /api/auth/login,传入用户名密码,获取access_token - 调用受保护接口时,在请求头添加
Authorization: Bearer <access_token> - 无令牌、令牌无效或无对应角色时,会返回401/403状态码
内容的提问来源于stack exchange,提问作者Kristina
相关产品推荐
相关产品推荐

