✨ 自定义UserDetailsService
This commit is contained in:
parent
285d9272f4
commit
6579c15627
|
@ -256,3 +256,41 @@ public class MD5PasswordEncoder implements PasswordEncoder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## 自定义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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
|
@ -1,11 +1,14 @@
|
||||||
package com.spring.security.config;
|
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.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.HttpMethod;
|
||||||
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
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.builders.HttpSecurity;
|
||||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||||
import org.springframework.security.web.SecurityFilterChain;
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
|
|
||||||
@EnableMethodSecurity
|
@EnableMethodSecurity
|
||||||
|
@ -18,7 +21,7 @@ public class SecurityWebConfiguration {
|
||||||
String[] permitAllUrls = {
|
String[] permitAllUrls = {
|
||||||
"/", "/doc.html/**",
|
"/", "/doc.html/**",
|
||||||
"/webjars/**", "/images/**", ".well-known/**", "favicon.ico", "/error/**",
|
"/webjars/**", "/images/**", ".well-known/**", "favicon.ico", "/error/**",
|
||||||
"/v3/api-docs/**"
|
"/swagger-ui/**", "/v3/api-docs/**"
|
||||||
};
|
};
|
||||||
|
|
||||||
http.authorizeHttpRequests(authorizeRequests ->
|
http.authorizeHttpRequests(authorizeRequests ->
|
||||||
|
@ -49,7 +52,14 @@ public class SecurityWebConfiguration {
|
||||||
.logout(logout -> logout
|
.logout(logout -> logout
|
||||||
.logoutSuccessUrl("/login-page?logout=true")
|
.logoutSuccessUrl("/login-page?logout=true")
|
||||||
.permitAll()
|
.permitAll()
|
||||||
);
|
)
|
||||||
|
.csrf(AbstractHttpConfigurer::disable)
|
||||||
|
.exceptionHandling(configurer -> configurer
|
||||||
|
.accessDeniedHandler(new SecurityAccessDeniedHandler())
|
||||||
|
.authenticationEntryPoint(new SecurityAuthenticationEntryPoint())
|
||||||
|
)
|
||||||
|
;
|
||||||
|
|
||||||
return http.build();
|
return http.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue