繁体   English   中英

Java - Spring - 由于未检测到事务,安全性无法正常工作

[英]Java - Spring - Security not working due to transaction not detected

我正在尝试构建一个带有安全层的简单 CRM spring 应用程序。

我的用例很简单:登录页面允许访问客户列表并从中添加新用户。

在此处输入图像描述

我为客户管理创建了一个客户端配置 class 和一个安全配置 class。 安全配置文件定义了它自己的数据源、事务管理器和 session 工厂以访问管理用户的专用数据库:

@Configuration
@EnableWebSecurity
@PropertySource("classpath:security-persistence-mysql.properties")
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    Environment env;
    private Logger logger = Logger.getLogger(getClass().getName());

    @Autowired
    private UserDetailsService userService;

    @Autowired
    private CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;

    @Bean(name = "securitySessionFactory")
    public LocalSessionFactoryBean sessionFactory() {
        LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
        sessionFactory.setDataSource(securityDataSource());
        sessionFactory.setHibernateProperties(hibernateProperties());
        sessionFactory.setPackagesToScan("com.luv2code.springdemo");

        return sessionFactory;
    }

    @Bean(name = "securityDataSource")
    public DataSource securityDataSource() {

        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        try {
            dataSource.setDriverClass(env.getProperty("jdbc.driver"));
        } catch (PropertyVetoException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        dataSource.setUser(env.getProperty("jdbc.user"));
        dataSource.setPassword(env.getProperty("jdbc.password"));
        dataSource.setJdbcUrl(env.getProperty("jdbc.security.url"));
        logger.info("URL security config : " + env.getProperty("jdbc.url"));

        dataSource.setInitialPoolSize(
                getPropertyAsInt("connection.pool.initialPoolSize"));
        dataSource.setMinPoolSize(
                getPropertyAsInt("connection.pool.minPoolSize"));
        dataSource.setMaxPoolSize(
                getPropertyAsInt("connection.pool.maxPoolSize"));
        dataSource.setMaxIdleTime(
                getPropertyAsInt("connection.pool.maxIdleTime"));

        return dataSource;
    }

    private int getPropertyAsInt(String key) {
        return Integer.parseInt(env.getProperty(key));
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth)
            throws Exception {

        auth.authenticationProvider(authenticationProvider());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/customer/**").hasRole("EMPLOYE")
                .antMatchers("/leaders/**").hasRole("MANAGER")
                .antMatchers("/systems/**").hasRole("ADMIN")
                .antMatchers("/", "/home", "/createUser").permitAll()
                .anyRequest().authenticated().and().formLogin()
                .loginPage("/showMyLoginPage")
                .loginProcessingUrl("/authentificateTheUser")
                .successHandler(customAuthenticationSuccessHandler).permitAll()
                .and().logout().permitAll().and().exceptionHandling()
                .accessDeniedPage("/access-denied");

    }

    private Properties hibernateProperties() {

        Properties hibernatePpt = new Properties();
        hibernatePpt.setProperty("hibernate.dialect",
                env.getProperty("hibernate.dialect"));
        hibernatePpt.setProperty("hibernate.show_sql",
                env.getProperty("hibernate.show_sql"));
        hibernatePpt.setProperty("hibernate.packagesToScan",
                env.getProperty("hibernate.packagesToScan"));

        return hibernatePpt;
    }

    @Bean(name = "securtiyTransactionManager")
    @Autowired
    @Qualifier("securitySessionFactory")
    public HibernateTransactionManager transactionManager(
            SessionFactory sessionFactory) {

        // setup transaction manager based on session factory
        HibernateTransactionManager txManager = new HibernateTransactionManager();
        txManager.setSessionFactory(sessionFactory);

        return txManager;
    }

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

    }

    @Bean
    public DaoAuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider auth = new DaoAuthenticationProvider();
        auth.setUserDetailsService(userService);
        auth.setPasswordEncoder(passwordEncoder());
        return auth;
    }

}

为了安全和登录,我没有使用默认用户管理,而是使用带有角色和用户实体的自定义用户管理:

@Entity
@Table(name = "user")
public class User {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;

@Column(name = "username")
private String userName;

@Column(name = "password")
private String password;

@Column(name = "first_name")
private String firstName;

@Column(name = "last_name")
private String lastName;

@Column(name = "email")
private String email;

@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinTable(name = "users_roles", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
private Collection<Role> roles;
//constructors, getter,setter

}

角色:

@Entity
@Table(name = "role")
public class Role {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

    @Column(name = "name")
    private String name;

//.....
}

我使用服务和 dao 层通过 hibernate 访问用户。

我的问题是,当我尝试登录或添加用户时出现异常: 原因:javax.persistence.TransactionRequiredException:没有事务正在进行

事情是使用事务注释。 首先我通过controller go:

@Controller
public class LoginController {
    @GetMapping("/showMyLoginPage")
    public String showMyLoginPage() {
        return "login";
    }

    @GetMapping("/access-denied")
    public String showAccesDenied() {

        return "access-denied";
    }
}

然后是 jsp:

<form:form method="POST" action="${pageContext.request.contextPath}/authenticateTheUser">

用户名:

密码:

</form:form>

public interface UserService extends UserDetailsService

@Service
@Transactional("securtiyTransactionManager")
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDAO userDAO;

    @Override
    public UserDetails loadUserByUsername(String userName)
            throws UsernameNotFoundException {
        User user = userDAO.getUser(userName);
        if (user == null) {
            throw new UsernameNotFoundException(
                    "Invalid username or password.");
        }
        return new org.springframework.security.core.userdetails.User(
                user.getUserName(), user.getPassword(),
                mapRolesToAuthorities(user.getRoles()));
    }




    private Collection<? extends GrantedAuthority> mapRolesToAuthorities(
            Collection<Role> roles) {
        return roles.stream()
                .map(role -> new SimpleGrantedAuthority(role.getName()))
                .collect(Collectors.toList());
    }
}

提交 jsp 时,它会调用用户服务详细信息(在配置类中自动装配)和事务下的 loadUserByUsername 方法:

 public interface UserService extends UserDetailsService @Service @Transactional("securtiyTransactionManager") public class UserServiceImpl implements UserService { @Autowired private UserDAO userDAO; @Override public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException { User user = userDAO.getUser(userName); if (user == null) { throw new UsernameNotFoundException( "Invalid username or password."); } return new org.springframework.security.core.userdetails.User( user.getUserName(), user.getPassword(), mapRolesToAuthorities(user.getRoles())); } private Collection<? extends GrantedAuthority> mapRolesToAuthorities( Collection<Role> roles) { return roles.stream().map(role -> new SimpleGrantedAuthority(role.getName())).collect(Collectors.toList()); } }

不知何故,交易不起作用,但我不知道为什么。 我并行我有管理客户用例的其他配置文件。

感谢任何帮助以了解问题所在。

有关完整项目的信息,请点击此处: https://github.com/moutyque/CRM

    @Bean(name = "securtiyTransactionManager")
    @Autowired
    public HibernateTransactionManager transactionManager(
             @Qualifier("securitySessionFactory") SessionFactory sessionFactory) {

        // setup transaction manager based on session factory
        HibernateTransactionManager txManager = new HibernateTransactionManager();
        txManager.setSessionFactory(sessionFactory);

        return txManager;
    }

我只能通过查看它来猜测您的错误。 您可以打开事务的日志级别以检查问题。 限定符可以内联在方法参数中,以确保 securitySessionFactory 是自动装配的。

暂无
暂无

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

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