Appearance
Spring Security面试题
1. Spring Security的基本概念
问题:什么是Spring Security?
答案:
- Spring Security:基于Spring框架的安全框架,用于保护Spring应用程序。
- 特点:
- 认证
- 授权
- 防护攻击
- 集成Spring
- 高度可定制
2. 认证和授权
问题:认证和授权有什么区别?
答案:
- 认证:验证用户的身份,确认用户是谁。
- 授权:验证用户的权限,确认用户能做什么。
3. Spring Security的架构
问题:Spring Security的架构是怎样的?
答案:
Spring Security架构
├── 认证
│ ├── 认证管理器
│ ├── 认证提供者
│ └── 用户详情服务
├── 授权
│ ├── 访问决策管理器
│ ├── 投票者
│ └── 安全拦截器
└── 防护攻击
├── CSRF
├── XSS
├── 点击劫持
└── 会话固定4. SecurityFilterChain
问题:SecurityFilterChain的作用是什么?
答案:
- SecurityFilterChain:Spring Security的核心组件,包含一系列过滤器。
- 作用:
- 处理HTTP请求
- 执行认证和授权
- 防护攻击
示例:
java
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/public/**").permitAll()
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.formLogin(form -> form
.loginPage("/login")
.permitAll()
)
.logout(logout -> logout
.permitAll()
);
return http.build();
}
}5. UserDetailsService
问题:UserDetailsService的作用是什么?
答案:
- UserDetailsService:用于加载用户信息。
- 作用:
- 根据用户名加载用户信息
- 返回UserDetails对象
示例:
java
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("User not found");
}
return new CustomUserDetails(user);
}
}6. UserDetails
问题:UserDetails的作用是什么?
答案:
- UserDetails:表示用户信息。
- 作用:
- 存储用户名
- 存储密码
- 存储权限
- 存储账户状态
示例:
java
public class CustomUserDetails implements UserDetails {
private User user;
public CustomUserDetails(User user) {
this.user = user;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return user.getRoles().stream()
.map(role -> new SimpleGrantedAuthority(role.getName()))
.collect(Collectors.toList());
}
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public String getUsername() {
return user.getUsername();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return user.isEnabled();
}
}7. PasswordEncoder
问题:PasswordEncoder的作用是什么?
答案:
- PasswordEncoder:用于密码加密和验证。
- 实现:
- BCryptPasswordEncoder
- Pbkdf2PasswordEncoder
- SCryptPasswordEncoder
- Argon2PasswordEncoder
示例:
java
@Configuration
public class SecurityConfig {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
// 使用
@Autowired
private PasswordEncoder passwordEncoder;
public void createUser(User user) {
String encodedPassword = passwordEncoder.encode(user.getPassword());
user.setPassword(encodedPassword);
userRepository.save(user);
}8. 认证方式
问题:Spring Security支持哪些认证方式?
答案:
- 表单登录:使用表单进行认证。
- HTTP Basic:使用HTTP Basic认证。
- HTTP Digest:使用HTTP Digest认证。
- X.509:使用证书认证。
- LDAP:使用LDAP认证。
- OAuth2:使用OAuth2认证。
- JWT:使用JWT认证。
9. 表单登录
问题:如何配置表单登录?
答案:
java
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.formLogin(form -> form
.loginPage("/login")
.loginProcessingUrl("/login")
.defaultSuccessUrl("/home")
.failureUrl("/login?error=true")
.usernameParameter("username")
.passwordParameter("password")
.permitAll()
);
return http.build();
}
}10. HTTP Basic认证
问题:如何配置HTTP Basic认证?
答案:
java
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.httpBasic(basic -> basic
.realmName("My Realm")
);
return http.build();
}
}11. JWT认证
问题:如何实现JWT认证?
答案:
java
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable())
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
)
.authorizeHttpRequests(auth -> auth
.requestMatchers("/auth/**").permitAll()
.anyRequest().authenticated()
)
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
}
// JWT过滤器
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Autowired
private JwtTokenProvider jwtTokenProvider;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String token = jwtTokenProvider.resolveToken(request);
if (token != null && jwtTokenProvider.validateToken(token)) {
Authentication auth = jwtTokenProvider.getAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(auth);
}
filterChain.doFilter(request, response);
}
}12. OAuth2
问题:什么是OAuth2?
答案:
- OAuth2:授权框架,用于第三方应用访问用户资源。
- 角色:
- 资源拥有者
- 客户端
- 授权服务器
- 资源服务器
- 授权模式:
- 授权码模式
- 简化模式
- 密码模式
- 客户端模式
13. 授权方式
问题:Spring Security支持哪些授权方式?
答案:
- 基于角色的授权:使用hasRole、hasAnyRole。
- 基于权限的授权:使用hasAuthority、hasAnyAuthority。
- 基于表达式的授权:使用@PreAuthorize、@PostAuthorize。
- 基于注解的授权:使用@Secured、@RolesAllowed。
示例:
java
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/admin/**").hasRole("ADMIN")
.requestMatchers("/user/**").hasAnyRole("ADMIN", "USER")
.requestMatchers("/api/**").hasAuthority("API_ACCESS")
.anyRequest().authenticated()
);
return http.build();
}
}
// 使用注解
@PreAuthorize("hasRole('ADMIN')")
public void adminMethod() {
}
@PreAuthorize("hasAuthority('API_ACCESS')")
public void apiMethod() {
}14. CSRF防护
问题:什么是CSRF?如何防护?
答案:
- CSRF(Cross-Site Request Forgery):跨站请求伪造,攻击者诱导用户执行非预期的操作。
- 防护方式:
- 使用CSRF Token
- 验证Referer头
- 使用SameSite Cookie
示例:
java
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
);
return http.build();
}
}15. CORS
问题:什么是CORS?如何配置?
答案:
- CORS(Cross-Origin Resource Sharing):跨域资源共享,允许浏览器跨域访问资源。
- 配置方式:
示例:
java
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.cors(cors -> cors.configurationSource(corsConfigurationSource()));
return http.build();
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("*"));
configuration.setAllowedHeaders(Arrays.asList("*"));
configuration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}16. 会话管理
问题:Spring Security如何管理会话?
答案:
- 会话创建策略:
- ALWAYS:总是创建会话。
- NEVER:不创建会话,如果需要会话则抛出异常。
- IF_REQUIRED:需要时创建会话。
- STATELESS:不创建会话,适用于JWT认证。
- 会话固定防护:防止会话固定攻击。
示例:
java
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.sessionFixation().migrateSession()
.maximumSessions(1)
.maxSessionsPreventsLogin(true)
);
return http.build();
}
}17. 记住我
问题:如何实现记住我功能?
答案:
java
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.rememberMe(remember -> remember
.key("uniqueAndSecret")
.tokenValiditySeconds(86400)
.userDetailsService(userDetailsService)
.rememberMeCookieName("remember-me")
);
return http.build();
}
}18. 匿名访问
问题:如何配置匿名访问?
答案:
java
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.anonymous(anonymous -> anonymous
.key("anonymousKey")
.authorities(new SimpleGrantedAuthority("ROLE_ANONYMOUS"))
)
.authorizeHttpRequests(auth -> auth
.requestMatchers("/public/**").permitAll()
.anyRequest().authenticated()
);
return http.build();
}
}19. 自定义过滤器
问题:如何添加自定义过滤器?
答案:
java
@Component
public class CustomFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
System.out.println("Custom Filter");
filterChain.doFilter(request, response);
}
}
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Autowired
private CustomFilter customFilter;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
}20. 自定义认证成功/失败处理
问题:如何自定义认证成功/失败处理?
答案:
java
@Component
public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {
response.sendRedirect("/home");
}
}
@Component
public class CustomAuthenticationFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException {
response.sendRedirect("/login?error=true");
}
}
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Autowired
private CustomAuthenticationSuccessHandler successHandler;
@Autowired
private CustomAuthenticationFailureHandler failureHandler;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.formLogin(form -> form
.successHandler(successHandler)
.failureHandler(failureHandler)
);
return http.build();
}
}21. 方法级安全
问题:如何实现方法级安全?
答案:
java
@Configuration
@EnableMethodSecurity
public class SecurityConfig {
}
@Service
public class UserService {
@PreAuthorize("hasRole('ADMIN')")
public void adminMethod() {
}
@PreAuthorize("hasAuthority('USER_READ')")
public User readUser() {
return new User();
}
@PreAuthorize("#userId == authentication.principal.id")
public User getUserById(int userId) {
return new User();
}
@PostFilter("filterObject.owner == authentication.principal.username")
public List<Document> getDocuments() {
return new ArrayList<>();
}
@PreFilter("filterObject.owner == authentication.principal.username")
public void saveDocuments(List<Document> documents) {
}
}22. 动态权限
问题:如何实现动态权限?
答案:
java
@Component
public class CustomPermissionEvaluator implements PermissionEvaluator {
@Autowired
private PermissionService permissionService;
@Override
public boolean hasPermission(Authentication authentication, Object targetId, Object permission) {
return permissionService.hasPermission(authentication, targetId, permission);
}
@Override
public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
return permissionService.hasPermission(authentication, targetId, targetType, permission);
}
}
@Configuration
@EnableMethodSecurity
public class SecurityConfig {
@Bean
public MethodSecurityExpressionHandler methodSecurityExpressionHandler() {
DefaultMethodSecurityExpressionHandler handler = new DefaultMethodSecurityExpressionHandler();
handler.setPermissionEvaluator(new CustomPermissionEvaluator());
return handler;
}
}23. 多租户
问题:如何在Spring Security中实现多租户?
答案:
java
@Component
public class TenantFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String tenantId = request.getHeader("X-Tenant-ID");
TenantContext.setTenantId(tenantId);
try {
filterChain.doFilter(request, response);
} finally {
TenantContext.clear();
}
}
}
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Autowired
private TenantFilter tenantFilter;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.addFilterBefore(tenantFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
}24. 社交登录
问题:如何实现社交登录?
答案:
java
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.oauth2Login(oauth2 -> oauth2
.loginPage("/login")
.userInfoEndpoint(userInfo -> userInfo
.userService(customOAuth2UserService)
)
);
return http.build();
}
}
@Service
public class CustomOAuth2UserService implements OAuth2UserService<OAuth2UserRequest, OAuth2User> {
@Override
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
OAuth2User oauth2User = delegate.loadUser(userRequest);
return processOAuth2User(oauth2User);
}
}25. Spring Security的最佳实践
问题:使用Spring Security的最佳实践有哪些?
答案:
- 使用强密码加密算法,如BCrypt。
- 使用HTTPS保护敏感数据。
- 使用CSRF Token防护CSRF攻击。
- 使用CORS配置跨域访问。
- 使用会话管理防止会话固定攻击。
- 使用方法级安全保护方法。
- 使用自定义过滤器实现自定义逻辑。
- 使用动态权限实现灵活的权限控制。
- 使用OAuth2实现第三方登录。
- 使用JWT实现无状态认证。
