spring-security 未调用Spring安全性+ jwt loadUserByUsername

oyt4ldly  于 2022-11-11  发布在  Spring
关注(0)|答案(1)|浏览(210)

[安全配置]

@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();
    }

}

[Jwt身份验证筛选器]

@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.登录尝试(用户,密码)
1.执行安全链
1.执行从UsernamePasswordAuthenticationFilter继承的筛选器
1.已确认ID和PW通常作为参数传递。
1.执行AuthenticationManager的authenticate()方法,检查ID和PW是否正确。
1.继承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
xu3bshqb

xu3bshqb1#

我回答自己是怎么找到它。

@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();

钥匙在这里。
我解决了这个问题,因为我已经定制和扩展的userDetailsService无法通知(无法注入)AuthenticationManager。

相关问题