我正在使用 Spring Security 6.2.1 和 Spring MVC 6.1.0
我想访问当前登录用户的用户名,如何从 SecurityContextHolder 访问用户详细信息? 从 spring security 5 更新到 6 起,当尝试通过从 SecurityContextHolder 获取身份验证来验证用户身份时,将返回 null。以前在使用 Spring Security/MVC 5 时,这没有任何问题。
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String name = authentication.getName();
String password = authentication.getCredentials().toString();
User user = authenticationDAO.getUser(name);
if (user != null && encoder.matches(password, user.getPassword())) {
List<String> roles = authenticationDAO.getRoles(user.getId());
List<GrantedAuthority> authorities = new ArrayList<>();
if (roles != null) {
for (String role : roles) {
authorities.add(new SimpleGrantedAuthority(role));
}
}
return new UsernamePasswordAuthenticationToken(name, password, authorities);
}
return null;
}
此时,当我稍后尝试访问应存储的用户名时,身份验证对象为空。
public String getAuthenticatedUser() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null || AnonymousAuthenticationToken.class.isAssignableFrom(authentication.getClass())) {
return null;
}
return authentication.getName();
}
假设您有自定义
UsernamePasswordAuthenticationFilter
,您必须明确提供并设置 SecurityContextRepository
。欲了解更多详细信息,请参见此处:
会话管理迁移
现在,如果这是您的情况,请声明一个专用 bean:
@Bean
public SecurityContextRepository delegatingSecurityContextRepository() {
return new DelegatingSecurityContextRepository(
new RequestAttributeSecurityContextRepository(),
new HttpSessionSecurityContextRepository());
}
然后将其注入到您的 UsernamePasswordAuthenticationFilter 中进行如下设置:
@Component
public class CustomUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private final SecurityContextRepository securityContextRepository;
private final AuthenticationFailureHandler authenticationFailureHandler;
private final AuthenticationSuccessHandler authenticationSuccessHandler;
@PostConstruct
private void setup() {
/* Settings must match those in the login-form */
super.setUsernameParameter("identifier");
super.setPasswordParameter("password");
super.setFilterProcessesUrl(AUTH_FORM_AUTHENTICATION_URL);
super.setSecurityContextRepository(securityContextRepository);
super.setAuthenticationFailureHandler(authenticationFailureHandler);
super.setAuthenticationSuccessHandler(authenticationSuccessHandler);
super.afterPropertiesSet();
}
public CustomUsernamePasswordAuthenticationFilter(
@Qualifier("customProviderManager") AuthenticationManager customProviderManager,
@Qualifier("delegatingSecurityContextRepository") SecurityContextRepository securityContextRepository,
@Qualifier("customAuthenticationFailureHandler") AuthenticationFailureHandler authenticationFailureHandler,
@Qualifier("customAuthenticationSuccessHandler") AuthenticationSuccessHandler authenticationSuccessHandler) {
this.securityContextRepository = securityContextRepository;
this.authenticationFailureHandler = authenticationFailureHandler;
this.authenticationSuccessHandler = authenticationSuccessHandler;
super.setAuthenticationManager(customProviderManager);
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
if (!request.getMethod().equals("POST"))
throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
String identifier = super.obtainUsername(request);
identifier = identifier != null ? identifier.trim() : "";
String password = super.obtainPassword(request);
password = password != null ? password : "";
CustomUsernamePasswordAuthenticationToken authRequest = CustomUsernamePasswordAuthenticationToken.unauthenticated(identifier, password);
super.setDetails(request, authRequest);
return super.getAuthenticationManager().authenticate(authRequest);
}
}