自定义UserDetailsService

This commit is contained in:
Bunny 2025-07-11 13:43:45 +08:00
parent 285d9272f4
commit 6579c15627
3 changed files with 85 additions and 2 deletions

View File

@ -255,4 +255,42 @@ public class MD5PasswordEncoder implements PasswordEncoder {
return true;
}
}
```
## 自定义UserDetailsService
在Spring Security中如果需要自定义用户认证逻辑可以通过实现`UserDetailsService`接口来完成。以下是正确实现方式:
### 标准实现示例
```java
@Service
public class CustomUserDetailsService implements UserDetailsService {
private final PasswordEncoder passwordEncoder;
// 推荐使用构造器注入
public CustomUserDetailsService(PasswordEncoder passwordEncoder) {
this.passwordEncoder = passwordEncoder;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 1. 这里应该根据username从数据库或其他存储中查询用户信息
// 以下是模拟数据,实际应用中应从数据库查询
// 2. 如果用户不存在抛出UsernameNotFoundException
if (!"bunny".equalsIgnoreCase(username)) {
throw new UsernameNotFoundException("User not found: " + username);
}
// 3. 构建UserDetails对象返回
return User.builder()
.username(username) // 使用传入的用户名
.password(passwordEncoder.encode("123456")) // 密码应该已经加密存储,这里仅为示例
.roles("USER") // 角色会自动添加ROLE_前缀
.authorities("read", "write") // 添加具体权限
.build();
}
}
```

View File

@ -1,11 +1,14 @@
package com.spring.security.config;
import com.spring.security.handler.SecurityAccessDeniedHandler;
import com.spring.security.handler.SecurityAuthenticationEntryPoint;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
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.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.web.SecurityFilterChain;
@EnableMethodSecurity
@ -18,7 +21,7 @@ public class SecurityWebConfiguration {
String[] permitAllUrls = {
"/", "/doc.html/**",
"/webjars/**", "/images/**", ".well-known/**", "favicon.ico", "/error/**",
"/v3/api-docs/**"
"/swagger-ui/**", "/v3/api-docs/**"
};
http.authorizeHttpRequests(authorizeRequests ->
@ -49,7 +52,14 @@ public class SecurityWebConfiguration {
.logout(logout -> logout
.logoutSuccessUrl("/login-page?logout=true")
.permitAll()
);
)
.csrf(AbstractHttpConfigurer::disable)
.exceptionHandling(configurer -> configurer
.accessDeniedHandler(new SecurityAccessDeniedHandler())
.authenticationEntryPoint(new SecurityAuthenticationEntryPoint())
)
;
return http.build();
}
}

View File

@ -0,0 +1,35 @@
package com.spring.security.service;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class CustomUserDetailsService implements UserDetailsService {
private final PasswordEncoder passwordEncoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 1. 这里应该根据username从数据库或其他存储中查询用户信息
// 以下是模拟数据实际应用中应从数据库查询
// 2. 如果用户不存在抛出UsernameNotFoundException
if (!"bunny".equalsIgnoreCase(username)) {
throw new UsernameNotFoundException("User not found: " + username);
}
// 3. 构建UserDetails对象返回
return User.builder()
.username(username) // 使用传入的用户名
.password(passwordEncoder.encode("123456")) // 密码应该已经加密存储这里仅为示例
.roles("USER") // 角色会自动添加ROLE_前缀
.authorities("read", "write") // 添加具体权限
.build();
}
}