在 Spring Boot 应用程序中实现 JWT 身份验证时出错 |找不到“org.hibernate.SessionFactory”

问题描述 投票:0回答:1

我正在尝试在 Spring Boot 应用程序中实现 JWT 身份验证,但遇到一些错误。请帮忙。 错误和日志位于本文档末尾

这是我的安全配置类

@Configuration
public class SecurityConfig {


    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    @Autowired
    private JwtFilter jwtFilter;



    @Bean
    public UserDetailsManager userDetailsManager(DataSource dataSource) {
        JdbcUserDetailsManager theUserDetailsManager = new JdbcUserDetailsManager(dataSource);
        theUserDetailsManager
                .setUsersByUsernameQuery("select user_email, user_password, enabled from chat_user where user_email=?");

        theUserDetailsManager.setAuthoritiesByUsernameQuery("select user_email, authority from authorities where user_email=?");
        return theUserDetailsManager;
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests(configurer -> configurer
                        .requestMatchers("/css/**", "/images/**").permitAll() //initially non authenticated users does not have access to css, so this is added
                        .requestMatchers("/showSignUpForm","/showLoginForm","/processSignUpForm").permitAll() // allow unauthenticated access to sign up page
                        .anyRequest().authenticated())
                        .csrf(AbstractHttpConfigurer::disable)
                        .addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class)
                        .formLogin(form -> form.loginPage("/showLoginForm")
                        .loginProcessingUrl("/authenticateTheUser")
                        .usernameParameter("user_email")
                        .passwordParameter("user_password")
                        .defaultSuccessUrl("/showChatPage", true)
                        .permitAll());
        return http.build();
    }
    
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

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

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

这是我的控制器


@RestController
@RequestMapping("/public")
@Slf4j
public class PublicController {

    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private UserDetailsServiceImpl userDetailsService;
    @Autowired
    private ChatUserService userService;

    @Autowired
    private JwtUtil jwtUtil;

    @GetMapping("/health-check")
    public String healthCheck() {
        return "Ok";
    }

    @PostMapping("/signup")
    public void signup(@RequestBody ChatUser user) {
        userService.saveChatUser(user);
    }

    @PostMapping("/login")
    public ResponseEntity<String> login(@RequestBody ChatUser user) {
        try{
            authenticationManager.authenticate(
                    new UsernamePasswordAuthenticationToken(user.getUser_email(), user.getUser_password()));
            UserDetails userDetails = userDetailsService.loadUserByUsername(user.getUser_email());
            String jwt = jwtUtil.generateToken(userDetails.getUsername());
            return new ResponseEntity<>(jwt, HttpStatus.OK);
        }catch (Exception e){
            log.error("Exception occurred while createAuthenticationToken ", e);
            return new ResponseEntity<>("Incorrect username or password", HttpStatus.BAD_REQUEST);
        }
    }
}

这是我的 JwtFilter 类

@Component
public class JwtFilter  extends OncePerRequestFilter{
    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private JwtUtil jwtUtil;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
        String authorizationHeader = request.getHeader("Authorization");
        String username = null;
        String jwt = null;
        if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
            jwt = authorizationHeader.substring(7);
            username = jwtUtil.extractUsername(jwt);
        }
        if (username != null) {
            UserDetails userDetails = userDetailsService.loadUserByUsername(username);
            if (jwtUtil.validateToken(jwt)) {
                UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                auth.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(auth);
            }
        }
        chain.doFilter(request, response);
    }
}

这是我的 UserDetailsServiceImpl 类

@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private ChatUserService chatUserService;


    @Override
    public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
        ChatUser user = chatUserService.findByUserEmail(email);
        if (user != null) {
            return org.springframework.security.core.userdetails.User.builder()
                    .username(user.getUser_email())
                    .password(user.getUser_password())
                    .roles("ROLE_USER")
                    .build();
        }
        throw new UsernameNotFoundException("User not found with username: " + email);
    }
}

ChatUserService接口

public interface ChatUserService {
    
    public List<ChatUser> getChatUsers();

    public void saveChatUser(ChatUser theChatUser);
    
    public ChatUser getChatUser(int theId);

    public void deleteChatUser(int theId);
    
    public ChatUser findByUsername(String username);
    
    public ChatUser findByUserEmail(String email);
    
}

ChatUserServiceImpl


@Service
public class ChatUserServiceImpl implements ChatUserService{

    @Autowired
    private ChatUserDAO chatUserDao;
    
    @Autowired
    private AuthorityDAO authorityDao;
    
    @Override
    @Transactional
    public List<ChatUser> getChatUsers() {
        return chatUserDao.getchatUsers();
    }

    @Override
    @Transactional
    public void saveChatUser(ChatUser theChatUser) {
        chatUserDao.saveChatUser(theChatUser);
        // Create and save the Authority
        Authority authority = new Authority(theChatUser.getUser_email(), "ROLE_USER");
        authorityDao.saveOrUpdateAuthority(authority);

        // Add the Authority to the ChatUser
        theChatUser.getAuthorities().add(authority);
  
    }
    
    @Override
    @Transactional
    public ChatUser getChatUser(int theId) {
        return chatUserDao.getChatUser(theId);
    }

    @Override
    @Transactional
    public void deleteChatUser(int theId) {
        chatUserDao.deleteChatUser(theId);
    }

    @Override
    @Transactional
    public ChatUser findByUsername(String username) {
        return chatUserDao.findByUsername(username);
    }

    @Override
    @Transactional
    public ChatUser findByUserEmail(String email) {
        return chatUserDao.findByUserEmail(email);
    }
    

}

ChatUserDAO 的类似接口 我的 ChatUserDAOImpl 类看起来像这样,它使用休眠会话工厂


@Repository
public class ChatUserDAOImpl implements ChatUserDAO{
    
    @Autowired
    private SessionFactory sessionFactory;

    @Override
    public List<ChatUser> getchatUsers() {
        Session currentSession = sessionFactory.getCurrentSession();
        Query<ChatUser> theQuery = currentSession.createQuery("from ChatUser", ChatUser.class);
        List<ChatUser> chatUsers = theQuery.getResultList();
        return chatUsers;
    }

    @SuppressWarnings("deprecation")
    @Override
    public void saveChatUser(ChatUser theChatUser) {
        Session currentSession = sessionFactory.getCurrentSession();
        currentSession.saveOrUpdate(theChatUser);   
    }

    @Override
    public ChatUser getChatUser(int theId) {
        Session currentSession = sessionFactory.getCurrentSession();
        ChatUser theChatUser = currentSession.get(ChatUser.class, theId);
        return theChatUser;
    }

    @Override
    public void deleteChatUser(int theId) {
        Session currentSession = sessionFactory.getCurrentSession();
        Query theQuery = currentSession.createQuery("delete from ChatUser where chat_id=:chatUserId");
        theQuery.setParameter("chatUserId", theId);
        theQuery.executeUpdate();
    }

    @Override
    public ChatUser findByUsername(String username) {
        Session currentSession = sessionFactory.getCurrentSession();
        Query<ChatUser> theQuery = currentSession.createQuery("from ChatUser where user_name=:u", ChatUser.class);
        theQuery.setParameter("u", username);
        try {
            return theQuery.getSingleResult();
        } catch (NoResultException nre) {
            return null;
        }
    }

    @Override
    public ChatUser findByUserEmail(String email) {
        Session currentSession = sessionFactory.getCurrentSession();
        Query<ChatUser> theQuery = currentSession.createQuery("from ChatUser where user_email=:e", ChatUser.class);
        theQuery.setParameter("e", email);
        try {
            return theQuery.getSingleResult();
        } catch (NoResultException nre) {
            return null;
        }
    }
}

当我尝试运行该应用程序时,出现此错误

描述:

com.springprojects.realtimechatapp.filter.JwtFilter 中的字段 userDetailsService 需要一个 bean,但找到了 2 个: - userDetailsServiceImpl:在文件 [C:...\service\UserDetailsServiceImpl.class] 中定义 - userDetailsManager:由类路径资源 [com/springprojects/.../SecurityConfig.class] 中的方法“userDetailsManager”定义

行动:

考虑将其中一个bean标记为@Primary,更新消费者以接受多个bean,或使用@Qualifier来标识应该使用的bean

我尝试过的 安全类中的 UserDetailsServiceImpl 实例不允许使用 @Primary。我在 UserDetailsManager 上尝试了@Primary,但现在它给了我这个错误:

说明: com.springprojects.realtimechatapp.dao.ChatUserDAOImpl 中的字段 sessionFactory 需要一个类型为“org.hibernate.SessionFactory”的 bean,但无法找到。 注入点有以下注释: - @org.springframework.beans.factory.annotation.Autowired(必需= true)

行动: 考虑在您的配置中定义“org.hibernate.SessionFactory”类型的 bean。

我对如何使用其中之一感到困惑。

spring spring-boot hibernate jwt
1个回答
0
投票

如果你打开

UserDetailsManager
的java文档,你会看到它
extends UserDetailsService
并且你也有自己的实现
UserDetailsServiceImpl
,这就是你得到:Field userDetailsService in com.springprojects.realtimechatapp.filter的原因。 JwtFilter 需要一个 bean,但找到了 2 个:

基于此,我建议您从

UserDetailsManager
中删除
SecurityConfig class
并保留您已经添加的
UserDetailsService

有关更多详细信息,以及使用

UserDetailsManager
或自己实现
UserDetailsService
有什么区别,您可以在此答案中找到 using-jdbcuserdetailsmanager-vs-own-userdetailsservice

© www.soinside.com 2019 - 2024. All rights reserved.