繁体   English   中英

spring 安全 + jwt loadUserByUsername 不调用

[英]spring security + jwt loadUserByUsername not call

[安全配置]

@Slf4j
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
    
    private final AuthenticationConfiguration authenticationConfiguration;
    
    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {

        httpSecurity
                .cors()
                .and()
                .csrf().disable()
                .formLogin().disable()
                .httpBasic().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                /*.headers().disable()*/
                .anyRequest().permitAll()
                .and()
                .addFilterBefore(new JwtAuthenticationFilter(authenticationManager(authenticationConfiguration)), UsernamePasswordAuthenticationFilter.class);
                
        return httpSecurity.build();
    }
    
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
    
}

[JwtAuthenticationFilter]

@RequiredArgsConstructor
@Slf4j
public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    private final AuthenticationManager authenticationManager;

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {

        log.info("Check Run");
        ObjectMapper om = new ObjectMapper();
        try {

            AdvertiserUserDto.Read read = om.readValue(request.getInputStream(), AdvertiserUserDto.Read.class);

            UsernamePasswordAuthenticationToken authenticationToken
                    = new UsernamePasswordAuthenticationToken(read.getUserLoginId(), read.getPassword());
            
            log.info(authenticationToken.getPrincipal().toString());
            log.info(authenticationToken.getCredentials().toString());

            return authenticationManager.authenticate(authenticationToken);
        }
        catch (IOException e) {
            e.printStackTrace();
            log.error("IO Exception");
        }
        return null;
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        log.info("Success");
        super.successfulAuthentication(request, response, chain, authResult);
    }

    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
        log.info("Fail");
        super.unsuccessfulAuthentication(request, response, failed);
    }
}

[安全用户详细信息服务]

@Slf4j
@RequiredArgsConstructor
@Service
public class SecurityUserDetailsService implements UserDetailsService {

    private final UserRepository userRepository;

    @Transactional
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        log.info("loadUserByUsername"); // **not Run**
        UserEntity user = userRepository.findByUserLoginId(username).orElseThrow(() -> new UsernameNotFoundException("no Search User"));

        return new SecurityUserDetails(
                user,
                /*Collections.singleton(new SimpleGrantedAuthority("ROLE_" + user.getType().getRoll()))*/
                Collections.singleton(new SimpleGrantedAuthority("ROLE_" + "USER"))
        );
    }
}

[安全用户详细信息]

@RequiredArgsConstructor
@Data
public class SecurityUserDetails implements UserDetails {

    private final UserEntity user;
    private final Collection<? extends GrantedAuthority> authorities;

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return authorities;
    }

    @Override
    public String getPassword() {
        return user.getPassword();
    }

    @Override
    public String getUsername() {
        return user.getUserId().toString();
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }

}

请注意,我在一个非常基本的水平上挣扎。

这是我到目前为止尝试过的过程:

  1. 登录尝试(用户,密码)

  2. 安全链被执行

  3. 执行一个继承自 UsernamePasswordAuthenticationFilter 的过滤器

  4. 已确认 ID 和 PW 正常作为参数传递。

  5. 执行AuthenticationManager的authenticate()方法检查ID和PW是否正确。

  6. 继承UserDeatilsService的loadUserByUsername()方法没有执行,立即执行unsuccessfulAuthentication()方法失败。

我附上代码。

根据我的计划,验证应该通过 loadUserByUsername() 来完成。

但是为什么验证工作没有执行就立即失败呢?

结果:

c.b.k.c.c.t.JwtAuthenticationFilter      : Check Run
c.b.k.c.c.t.JwtAuthenticationFilter      : test
c.b.k.c.c.t.JwtAuthenticationFilter      : 1234
c.b.k.c.c.t.JwtAuthenticationFilter      : Fail

我回答自己是如何找到它的。

@Slf4j
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {

    private final SecurityUserDetailsService securityUserDetailsService;

    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {

        AuthenticationManagerBuilder authenticationManagerBuilder = httpSecurity.getSharedObject(AuthenticationManagerBuilder.class);
        authenticationManagerBuilder.userDetailsService(securityUserDetailsService);
        AuthenticationManager authenticationManager = authenticationManagerBuilder.build();

        httpSecurity
                .cors()
                .and()
                .csrf().disable()
                .formLogin().disable()
                .httpBasic().disable()
                .authenticationManager(authenticationManager)
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                /*.headers().disable()*/
                .anyRequest().permitAll()
                .and()
                .addFilterBefore(new JwtAuthenticationFilter(authenticationManager), UsernamePasswordAuthenticationFilter.class);

        return httpSecurity.build();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

}

以下是我如何通过其他建议发现并成功的。

我认为这种方法存在一些问题或需要改进的地方。

我不知道这是否是正确的方法,但我正在为他人和改进而写下来。

AuthenticationManagerBuilder authenticationManagerBuilder = httpSecurity.getSharedObject(AuthenticationManagerBuilder.class);
        authenticationManagerBuilder.userDetailsService(securityUserDetailsService);
        AuthenticationManager authenticationManager = authenticationManagerBuilder.build();

关键在这里。

我解决了这个问题,因为无法将我自定义和扩展的 userDetatilsService 通知(无法注入)到 AuthenticationManager。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM