未调用自定义 Spring UserDetailsService
Custom Spring UserDetailsService not called
我正在尝试为当前登录的用户添加一些自定义数据,所以我发现我可以实现自己的 UserDetailsService 并将其插入 Spring,但它从未被调用,我总是得到 Principal作为用户名字符串。
我有 UserDetailsService 的实现:
@Service
public class UserDetailServiceImpl implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
...
}
}
我对 UserDetails 的实现:
import org.springframework.security.core.userdetails.User;
public class LoggedInUser extends User {
...
}
并尝试通过多种方式在配置 (SecurityConfiguration) 中进行设置:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private CustomAuthenticationProvider customAuthProvider;
@Autowired
private UserDetailsService userDetailServiceImpl;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(customAuthProvider);
auth.userDetailsService(userDetailServiceImpl).passwordEncoder(passwordService.getPasswordEncoder());
}
...
}
或
@Autowired
protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(customAuthProvider);
auth.userDetailsService(userDetailServiceImpl).passwordEncoder(passwordService.getPasswordEncoder());
}
或
@Override
@Bean
public UserDetailsService userDetailsService() {
return new UserDetailServiceImpl();
}
没有任何效果...我尝试通过多种方式检索用户信息:
- 在带有@AuthenticationPrincipal 的控制器中我得到 null
正在使用中(我收到无效的转换错误):
认证认证=SecurityContextHolder.getContext().getAuthentication();
(登录用户)authentication.getPrincipal()
知道为什么它不起作用吗?我的 impl class 是否默认被其他地方覆盖?我试图查看日志 (logging.level.org.springframework.security=TRACE) 但没有运气:/
我可以登录,一切正常,只是主要数据始终只是用户名字符串,而不是我的 class.
ILya Cyclone 的评论是找出问题所在的关键,在再次检查 CustomAuthenticationProvider
后我注意到在返回数据时您可以指定 Principal
,而不必只是用户名, 但你可以在那里添加你的自定义 UserDetails
并且因为那个自定义 UserDetailsService
没有被调用,这是我假设它总是被调用的错误。
所以最后这足以让自定义 AuthenticationProvider
和自定义 UserDetails
:
@Service
public class CustomAuthenticationProvider implements AuthenticationProvider {
@Autowired
private UserService userService;
@Autowired
private PasswordService passwordService;
@Override
public Authentication authenticate(Authentication auth) throws AuthenticationException {
String username = auth.getName();
String password = auth.getCredentials().toString();
User user = userService.getUserWithPermissionsByName(username);
if (user == null) {
throw new BadCredentialsException("invalid_username_or_pass");
}
if (!passwordService.passwordsMatch(password, user.getPassword())) {
throw new BadCredentialsException("invalid_username_or_pass");
}
String[] permissions = user.getPermissions().stream().map((p) -> p.getName()).toArray(String[]::new);
List<GrantedAuthority> grantedAuths = AuthorityUtils.createAuthorityList(permissions);
return new UsernamePasswordAuthenticationToken(new LoggedInUser(user.getName(), user.getPassword(), true, true, true, true, grantedAuths, user.getId()),
password, grantedAuths);
}
@Override
public boolean supports(Class<?> auth) {
return auth.equals(UsernamePasswordAuthenticationToken.class);
}
}
我正在尝试为当前登录的用户添加一些自定义数据,所以我发现我可以实现自己的 UserDetailsService 并将其插入 Spring,但它从未被调用,我总是得到 Principal作为用户名字符串。
我有 UserDetailsService 的实现:
@Service
public class UserDetailServiceImpl implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
...
}
}
我对 UserDetails 的实现:
import org.springframework.security.core.userdetails.User;
public class LoggedInUser extends User {
...
}
并尝试通过多种方式在配置 (SecurityConfiguration) 中进行设置:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private CustomAuthenticationProvider customAuthProvider;
@Autowired
private UserDetailsService userDetailServiceImpl;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(customAuthProvider);
auth.userDetailsService(userDetailServiceImpl).passwordEncoder(passwordService.getPasswordEncoder());
}
...
}
或
@Autowired
protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(customAuthProvider);
auth.userDetailsService(userDetailServiceImpl).passwordEncoder(passwordService.getPasswordEncoder());
}
或
@Override
@Bean
public UserDetailsService userDetailsService() {
return new UserDetailServiceImpl();
}
没有任何效果...我尝试通过多种方式检索用户信息:
- 在带有@AuthenticationPrincipal 的控制器中我得到 null
正在使用中(我收到无效的转换错误):
认证认证=SecurityContextHolder.getContext().getAuthentication(); (登录用户)authentication.getPrincipal()
知道为什么它不起作用吗?我的 impl class 是否默认被其他地方覆盖?我试图查看日志 (logging.level.org.springframework.security=TRACE) 但没有运气:/ 我可以登录,一切正常,只是主要数据始终只是用户名字符串,而不是我的 class.
ILya Cyclone 的评论是找出问题所在的关键,在再次检查 CustomAuthenticationProvider
后我注意到在返回数据时您可以指定 Principal
,而不必只是用户名, 但你可以在那里添加你的自定义 UserDetails
并且因为那个自定义 UserDetailsService
没有被调用,这是我假设它总是被调用的错误。
所以最后这足以让自定义 AuthenticationProvider
和自定义 UserDetails
:
@Service
public class CustomAuthenticationProvider implements AuthenticationProvider {
@Autowired
private UserService userService;
@Autowired
private PasswordService passwordService;
@Override
public Authentication authenticate(Authentication auth) throws AuthenticationException {
String username = auth.getName();
String password = auth.getCredentials().toString();
User user = userService.getUserWithPermissionsByName(username);
if (user == null) {
throw new BadCredentialsException("invalid_username_or_pass");
}
if (!passwordService.passwordsMatch(password, user.getPassword())) {
throw new BadCredentialsException("invalid_username_or_pass");
}
String[] permissions = user.getPermissions().stream().map((p) -> p.getName()).toArray(String[]::new);
List<GrantedAuthority> grantedAuths = AuthorityUtils.createAuthorityList(permissions);
return new UsernamePasswordAuthenticationToken(new LoggedInUser(user.getName(), user.getPassword(), true, true, true, true, grantedAuths, user.getId()),
password, grantedAuths);
}
@Override
public boolean supports(Class<?> auth) {
return auth.equals(UsernamePasswordAuthenticationToken.class);
}
}