Files
spring-boot-3.5.0-keycloak-24/src/main/java/com/tanqidi/survey/config/OAuth2LoginSecurityConfig.java
tanqidi 01108a1782 update
2025-07-14 17:38:58 +08:00

107 lines
5.6 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.tanqidi.survey.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.web.cors.CorsConfiguration;
import java.util.*;
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class OAuth2LoginSecurityConfig {
@Bean
public JwtAuthenticationConverter jwtAuthenticationConverter() {
JwtAuthenticationConverter converter = new JwtAuthenticationConverter();
converter.setJwtGrantedAuthoritiesConverter(jwt -> {
Collection<GrantedAuthority> authorities = new ArrayList<>();
Object realmAccess = jwt.getClaim("realm_access");
if (realmAccess instanceof Map<?, ?> map) {
Object roles = map.get("roles");
if (roles instanceof Collection<?> roleList) {
for (Object role : roleList) {
// System.out.println("ROLE_" + role);
authorities.add(new SimpleGrantedAuthority("ROLE_" + role));
}
}
}
return authorities;
});
return converter;
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.cors(cors -> cors.configurationSource(request -> {
CorsConfiguration configuration = new CorsConfiguration();
// String originsProp = env.getProperty("cors.allowed-origins");
// 你的前端调试地址防止出现跨域。可以稍微修改下代码做成从application.properties中读取
String originsProp = "http://localhost:3000,http://localhost:3002,";
if (!originsProp.isBlank()) {
configuration.setAllowedOrigins(Arrays.asList(originsProp.split(",")));
}
// 只允许常用的安全方法,满足前端常见请求
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"));
// 允许所有请求头便于前端携带token等自定义头
configuration.setAllowedHeaders(Arrays.asList("*"));
// 允许携带cookie和认证信息适合需要登录态的前后端分离场景
configuration.setAllowCredentials(true);
return configuration;
}))
.sessionManagement(sessionManagement ->
sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
// .requestMatchers("/login", "/logout", "/error").permitAll()
.requestMatchers("/api/admin/**").hasRole("test-service-admin") //
.requestMatchers("/api/user/**").hasAnyRole("test-service-user", "test-service-admin") //
.anyRequest().authenticated())
.oauth2ResourceServer(oauth2 -> oauth2
.jwt(jwt -> jwt.jwtAuthenticationConverter(jwtAuthenticationConverter())) // 设置JWT权限转换器支持自定义角色映射
.authenticationEntryPoint(unauthorizedEntryPoint()) // 指定自定义401响应token过期/无效也会返回JSON
)
.exceptionHandling(handling -> handling
.accessDeniedHandler(accessDeniedHandler())); // 全局无权限处理
return http.build();
}
@Bean
public AuthenticationEntryPoint unauthorizedEntryPoint() {
return (request, response, authException) -> {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentType("application/json;charset=UTF-8");
Map<String, Object> result = new HashMap<>();
result.put("code", 401);
result.put("message", "您的访问令牌无效或已过期,请重新登录后再试。"); // 优雅提示
result.put("data", null);
response.getWriter().write(new ObjectMapper().writeValueAsString(result)); // 返回自定义JSON格式
};
}
@Bean
public AccessDeniedHandler accessDeniedHandler() {
return (request, response, accessDeniedException) -> {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
response.setContentType("application/json;charset=UTF-8");
Map<String, Object> result = new HashMap<>();
result.put("code", 403);
result.put("message", "权限不足,您无权访问该资源。"); // 简洁优雅提示
result.put("data", null);
response.getWriter().write(new ObjectMapper().writeValueAsString(result));
};
}
}