首页 > 解决方案 > AuthenticationManager 的扩展点

问题描述

我正在使用 Spring Security 进行简单的登录:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebAuthenticationConfig extends WebSecurityConfigurerAdapter {

    private final PasswordEncoder passwordEncoder;
    private final UserDetailServiceImpl userDetailsService;

    @Autowired
    public WebAuthenticationConfig(PasswordEncoder passwordEncoder, UserDetailServiceImpl userDetailsService) {
        this.passwordEncoder = passwordEncoder;
        this.userDetailsService = userDetailsService;
    }

    @Override
    public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
        authenticationManagerBuilder.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
    }

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity
                .cors()
                .and()
                .csrf()
                .disable()
           
                .authorizeRequests()
                .antMatchers(
                        "/register/*",
                        "/login").permitAll()
                .anyRequest().authenticated()
                .and()
                .exceptionHandling()
                
                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    
    }


    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}

如您所见,我使用的是默认 AuthManager。现在UserDetailServiceImpl很简单:

@Service
public class UserDetailServiceImpl implements UserDetailsService {

    private final UserRepository userRepository;

    @Autowired
    public UserDetailServiceImpl(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Override
    public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
        Optional<UserEntity> dbUser = userRepository.findUserByEmail(email);
        if (!dbUser.isPresent()) {
            throw new UsernameNotFoundException("No user found with email " + email);
        }

        UserEntity user = dbUser.get();

        return UserDetailsImpl.build(user);
    }
}

在我的控制器中,我使用它,例如:

@RequestMapping(value = "login", method = RequestMethod.POST)
public void loginUser(@Valid @RequestBody LoginUserRequest request, HttpServletRequest httpServletRequest) {
    Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(request.getEmail(), request.getPassword()));
    SecurityContextHolder.getContext().setAuthentication(authentication);
}

这工作得很好,身份验证管理器调用getUserByEmailUserDetailServiceImpl找到用户,然后 authenticationManager 比较密码并返回身份验证对象。

但是,如果我想在此过程中进行其他操作怎么办?如果我想记录被登录用户的 IP 地址怎么办?

我可以从控制器中提取 IP 地址,但是我实际上可以插入此功能HttpServletRequest的扩展点在哪里?AuthenticationManager

我可以扩展AbstractAuthenticationToken以接受有关令牌的详细信息(所以在我的情况下,除了电子邮件和密码之外,我还会通过 IP 地址进行身份验证)。

然后我可以实现我自己的AuthenticationManager,所以它不需要我的实现UserDetailService,因此我的AuthenticationManager看起来像:

public class MyAuthenticationManager implements AuthenticationManager{
    
    @Autowired
    private final UserRepository;
    
    @Autowired
    private final PasswordEncoder passwordEncoder;

    Authentication authenticate(Authentication authentication) throws AuthenticationException{
       MyAuthToken token = (MyAuthToken) authentication;

       UserEntity user = userRepository.findUserByEmail(token.getName);
       // check if user exists and if password matches
      
       userRepository.addIp(token.getIP());
    }
  
}

但是我会失去整个身份验证管理器流程,我不确定它是否好,因为它看起来很健壮。

是否有任何扩展点可以插入我的功能?

感谢帮助

标签: javaspringspring-security

解决方案


推荐阅读