【问题标题】:Spring boot security | Why does my authenticationManager not work?Spring Boot 安全性 |为什么我的 authenticationManager 不起作用?
【发布时间】:2021-03-24 13:34:48
【问题描述】:

所以我正在制作我的第一个 Spring Boot 项目(我正在制作一个 RESTful 后端 API)并且遇到了 jwt 身份验证。在尝试了一些教程后,我一直卡住,直到一个教程对我有所帮助。

我的问题:

当我运行我的 AuthenticationController 时:

@RestController
@CrossOrigin
public class JwtAuthenticationController {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;


    @Autowired
    private JwtUserDetailsService userDetailsService;

    @RequestMapping(value = "/authenticate", method = RequestMethod.POST)
    public ResponseEntity<?> createAuthenticationToken(@RequestBody JwtRequest authenticationRequest) throws Exception {

       try {
            authenticationManager.authenticate(
                    new UsernamePasswordAuthenticationToken(authenticationRequest.getUsername(), authenticationRequest.getPassword())
            );} catch (BadCredentialsException e){
            throw new Exception("Incorrect username or password", e);
        }


        final UserDetails userDetails = userDetailsService
                .loadUserByUsername(authenticationRequest.getUsername());

        final String token = jwtTokenUtil.generateToken(userDetails);


        return ResponseEntity.ok(new JwtResponse(token));
    }

    @RequestMapping(value = "/register", method = RequestMethod.POST)
    public ResponseEntity<?> saveUser(@RequestBody UserDTO user) throws Exception {
        return ResponseEntity.ok(userDetailsService.save(user));
    }
}

我的代码没有跑过这段代码:

try {
            authenticationManager.authenticate(
                    new UsernamePasswordAuthenticationToken(authenticationRequest.getUsername(), authenticationRequest.getPassword())
            );} catch (BadCredentialsException e){
            throw new Exception("Incorrect username or password", e);
        }

我知道这一点基本上是因为调试。它总是抓住机会,我不知道为什么。 当我注释掉那段不工作的代码时,我的代码会运行,但我可以将任何用户名和密码与给定的 jwt 令牌一起使用,这不是我想要的。

所以我知道确保我的程序没有按计划运行的那段代码就是那段代码。

我知道不工作的代码使用了我的 JwtRequest,所以也许有人需要它来帮助我解决我的问题:

JwtRequest:

package com.example.demo.Model;

public class JwtRequest{

  

    private String username;
    private String password;

    public JwtRequest() {
    }

    public JwtRequest(String username, String password) {
        this.username = username;
        this.password = password;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

这是我的调试器和数据库,用于确认凭据是否正确:

我的调试器:

我的数据库:

我的邮递员:

我尝试过的:

我已尝试替换此代码:

 try {
            authenticationManager.authenticate(
                    new UsernamePasswordAuthenticationToken(authenticationRequest.getUsername(), authenticationRequest.getPassword())
            );} catch (BadCredentialsException e){
            throw new Exception("Incorrect username or password", e);
        }

有了这个:

authenticate(authenticationRequest.getUsername(), authenticationRequest.getPassword());

以及我相应的身份验证方法:

private void authenticate(String username, String password) throws Exception {
    try {
        authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
    } catch (DisabledException e) {
        throw new Exception("USER_DISABLED", e);
    } catch (BadCredentialsException e) {
        throw new Exception("INVALID_CREDENTIALS", e);
    }
}

然后我的调试器说:

我基本上被卡住了,我现在不知道该怎么办。任何人都可以帮助我或为我提供有关如何使用未过时且教程中包含源代码的 MYSQL 数据库实现 JWT 身份验证的教程吗? 谢谢! 如果您需要一些代码,请询问,我会在帖子中包含它。

根据要求提供以下文件:

WebSecurityConfig:

@Configuration
@AllArgsConstructor
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {//provides security for endpoints

    @Autowired
    private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;

    @Autowired
    private UserDetailsService jwtUserDetailsService;

    @Autowired
    private JwtRequestFilter jwtRequestFilter;

    private final AccountService accountService;
    private final BCryptPasswordEncoder bCryptPasswordEncoder;

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        // configure AuthenticationManager so that it knows from where to load
        // user for matching credentials
        // Use BCryptPasswordEncoder
        auth.userDetailsService(jwtUserDetailsService).passwordEncoder(bCryptPasswordEncoder);
    }

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

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()//So we can send post requests without being rejected(if we using form based indication we want to enable this)
                .authorizeRequests()
                .antMatchers("/authenticate","/register")
                .permitAll()//any request that goes trough that end point we want to allow.
                .anyRequest()
                .authenticated().and().exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint)
                .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and().addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);

    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(daoAuthenticationProvider());
    }

    @Bean
    public DaoAuthenticationProvider daoAuthenticationProvider() {
        DaoAuthenticationProvider provider =
                new DaoAuthenticationProvider();
        provider.setPasswordEncoder(bCryptPasswordEncoder);
        provider.setUserDetailsService(accountService);
        return provider;
    }
}

密码编码器:

@Configuration
public class PasswordEncoder{

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder(){
        return new BCryptPasswordEncoder();
    }




}

用户详情服务:

@Service
public class JwtUserDetailsService implements UserDetailsService {
    @Autowired
    private UserDao userDao;
    @Autowired
    private PasswordEncoder bcryptEncoder;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        DAOUser user = userDao.findByUsername(username);
        if (user == null){
            throw new UsernameNotFoundException("User not found with username: " + username);
        }
        return new User(user.getUsername(), user.getPassword(), new ArrayList<>());

    }
    public DAOUser save(UserDTO user) {
        DAOUser newUser = new DAOUser();
        newUser.setUsername(user.getUsername());
        newUser.setPassword(bcryptEncoder.bCryptPasswordEncoder().encode(user.getPassword()));
        return userDao.save(newUser);
    }
}

【问题讨论】:

  • 还请分享您的安全配置和UserDetailsService。如果您想采取不同的方式,可以查看此JWT login 示例,尽管架构与您当前使用的不同。
  • 是否提供了passwordEncoder bean?请显示您的安全配置
  • @EleftheriaStein-Kousathana 我添加了它
  • @ArfatBinkileb 我添加了它

标签: java authentication spring-security jwt


【解决方案1】:
@Bean
    public DaoAuthenticationProvider daoAuthenticationProvider() {
        DaoAuthenticationProvider provider =
                new DaoAuthenticationProvider();
        provider.setPasswordEncoder(bCryptPasswordEncoder);
        provider.setUserDetailsService(accountService);
        return provider;
    }

您将accountService 设置为userDetailsService 而不是`JwtUserDetailsS​​ervice'。你试过吗?

更改JwtUserDetailsService.java

    //not sure why accountService-> don't make it final
    //@Autowired //missing
    //private AccountService accountService;
    @Autowired
    private PasswordEncoder bcryptEncoder;

@Configuration
@AllArgsConstructor
//@EnableWebSecurity not needed
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {//provides security for endpoints

    @Autowired
    private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;

    @Autowired
    private JwtUserDetailsService jwtUserDetailsService;

    @Autowired
    private JwtRequestFilter jwtRequestFilter;

    //private AccountService accountService;
    @Autowired 
    private PasswordEncoder bCryptPasswordEncoder;

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        // configure AuthenticationManager so that it knows from where to load
        // user for matching credentials
        // Use BCryptPasswordEncoder
        auth.userDetailsService(jwtUserDetailsService).passwordEncoder(bCryptPasswordEncoder);
    }

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

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()//So we can send post requests without being rejected(if we using form based indication we want to enable this)
                .authorizeRequests()
                .antMatchers("/authenticate","/register")
                .permitAll()//any request that goes trough that end point we want to allow.
                .anyRequest()
                .authenticated().and().exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint)
                .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
                //.and().addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class); You are not using filter to authenticate, you are using a controller for that

    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(daoAuthenticationProvider());
    }

    @Bean
    public DaoAuthenticationProvider daoAuthenticationProvider() {
        DaoAuthenticationProvider provider =
                new DaoAuthenticationProvider();
        provider.setPasswordEncoder(bCryptPasswordEncoder);
        //provider.setUserDetailsService(accountService);
        return provider;
    }
}

【讨论】:

    猜你喜欢
    • 2019-08-12
    • 2019-12-18
    • 1970-01-01
    • 2015-11-15
    • 2021-12-27
    • 2019-08-25
    • 2016-06-23
    • 1970-01-01
    • 2017-01-10
    相关资源
    最近更新 更多