我添加了“TenantID”到登录页面,使用用户名和密码验证登录用户,并添加了“CustomAuthenticationFilter”,“CustomAuthenticationProvider”,“MethodSecurityConfig”,“SuccessHandler”并将其附加到“SecurityConfig”。
然后,它可以通过”成功处理器“上的“安全上下文保持器.getContext(). getAuthentication().getPrincipal()”获取用户数据,该“成功处理器”实现了“验证成功处理器”。
但是,控制器上的AuthenticationPrincipal为空。我想告诉我原因以及如何修复它。
用途:SpringBoot3.0.4、SpringSecurity6.0.2使用“网络安全配置器适配器”的“SpringSecurity5.2.2”没有问题
安全配置
@EnableWebSecurity
@Configuration
public class SecurityConfig {
@Autowired
@Qualifier("SuccessHandler")
AuthenticationSuccessHandler successHandler;
@Autowired
@Qualifier("UserDetailsServiceImpl")
private UserDetailsService userDetailsService;
//Bean by PasswordEncoder
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Autowired
private DataSource dataSource;
@Autowired
@Qualifier("CustomAuthenticationProvider")
private AuthenticationProvider authenticationProvider;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.csrf(csrf -> csrf.disable());
http.headers(head -> head.frameOptions().disable());
http
.authorizeHttpRequests(authz -> authz.requestMatchers("/login").permitAll()
.anyRequest().authenticated());
http
.formLogin()
// .loginProcessingUrl("/login")
.loginPage("/login");
// .failureUrl("/login?error")
// .usernameParameter("userId")
// .passwordParameter("password")
// //.defaultSuccessUrl("/home", true);
// .successHandler(successHandler);
// Login-filters
CustomAuthenticationFilter filter = new CustomAuthenticationFilter();
filter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/login", "POST"));
filter.setAuthenticationManager(authenticationManagerBean());
filter.setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler("/login?error"));
filter.setAuthenticationSuccessHandler(successHandler);
http.addFilterBefore(filter, CustomAuthenticationFilter.class);
// Logout
http
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutUrl("/logout")
.logoutSuccessUrl("/login");
return http.build();
}
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
AuthenticationManager auth = new ProviderManager(authenticationProvider);
System.out.println("AuthenticationManager");
System.out.println(auth);
return new ProviderManager(authenticationProvider);
}
}
自定义身份验证筛选器
public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) {
// ユーザー生成
AppUserDetails user = new AppUserDetails();
user.setTenantId(request.getParameter("tenantId"));
user.setUserId(request.getParameter("userId"));
// パスワード取得
String password = obtainPassword(request);
// トークンの作成
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(user, password);
// リクエストの詳細をセットしておく
setDetails(request, authRequest);
Authentication authz = this.getAuthenticationManager().authenticate(authRequest);
System.out.println("aaaaaaaauth");
System.out.println(authz);
// 認証の実施
return authz;
}
}
自定义身份验证提供程序
@Component("CustomAuthenticationProvider")
@Slf4j
public class CustomAuthenticationProvider implements AuthenticationProvider {
@Autowired
UserDetailsServiceImpl service;
@Autowired
MessageSource messageSource;
/** メッセージのキー(認証失敗) */
private static final String BAD_CREDENTIALS = "AbstractUserDetailsAuthenticationProvider.badCredentials";
/*
* 認証処理を行うメソッド.
*/
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// ユーザー取得(リクエストから)
AppUserDetails user = (AppUserDetails)authentication.getPrincipal();
// パスワード取得(リクエストから)
String password = (String)authentication.getCredentials();
// ユーザー取得(DBから)
user = (AppUserDetails) service.loadUserByUsernameAndTenantId(user.getUserId(), user.getTenantId());
// パスワードチェック
checkPassword(password, user.getPassword());
// 各種チェック
UserDetailsChecker checker = new AccountStatusUserDetailsChecker();
checker.check(user);
// トークンを生成
return new UsernamePasswordAuthenticationToken(user, password, user.getAuthorities());
}
/*
* 認証処理を実施するクラスの制限.
*/
@Override
public boolean supports(Class<?> authentication) {
return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
}
/**
* パスワードチェック.
*/
private void checkPassword(String rawPassword, String encodedPassword) {
PasswordEncoder encoder = new BCryptPasswordEncoder();
// パスワードが一致しているかどうか
if(encoder.matches(rawPassword, encodedPassword) == false) {
// エラーメッセージ取得
String message = messageSource.getMessage(BAD_CREDENTIALS,
null,
Locale.getDefault());
// 例外を投げる
throw new BadCredentialsException(message);
}
}
}
方法安全配置
@Configuration
@EnableMethodSecurity(prePostEnabled = true,securedEnabled = true,jsr250Enabled = true)
public class MethodSecurityConfig {
}
成功处理程序
@Component("SuccessHandler")
@Slf4j
public class SuccessHandler implements AuthenticationSuccessHandler {
@Autowired
UserDetailsServiceImpl service;
@Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
log.info("ログイン成功イベント開始");
// ユーザー情報の取得
AppUserDetails user = (AppUserDetails) SecurityContextHolder
.getContext()
.getAuthentication()
.getPrincipal();
log.info(user.toString());
String redirectPath = request.getContextPath();
// パスワード更新日付のチェック
if(user.getPassUpdateDate().after(new Date())) {
// パスワード期限が切れてない
log.info("遷移先:ホーム");
redirectPath += "/home";
} else {
// パスワード期限切れ
log.info("遷移先:パスワード変更");
redirectPath += "/password/change";
}
log.info("ログイン成功イベント終了");
response.sendRedirect(redirectPath);
}
}
家庭控制器
public class HomeController {
@GetMapping("/home")
@PreAuthorize("hasAuthority('ROLE_ADMIN') or hasAuthority('ROLE_GENERAL')")
public String getHome(Model model,
@AuthenticationPrincipal AppUserDetails user) {
log.info("HomeController Start");
log.info(user.toString());
log.info("HomeController End");
return "home";
}
我希望将用户数据传递到控制器中的AuthenticationPrincipal
1条答案
按热度按时间oyxsuwqo1#
我下定决心
我将这段代码添加到“响应”之前的“成功处理程序”中。“
并添加以下代码
此问题的原因是未存储“身份验证”
参考:https://docs.spring.io/spring-security/reference/servlet/authentication/session-management.html#store-authentication-manually