java - Java - Spring - 由于未检测到事务,安全性不起作用
问题描述
我正在尝试构建一个带有安全层的简单 CRM spring 应用程序。
我的用例很简单:登录页面允许访问客户列表并从中添加新用户。
我为客户管理和安全配置类创建了一个客户端配置类。安全配置文件定义了它自己的数据源、事务管理器和会话工厂来访问管理用户的专用数据库:
@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 层通过休眠访问用户。
我的问题是,当我尝试登录或添加用户时出现异常: 原因:javax.persistence.TransactionRequiredException:没有事务正在进行
事情是使用事务注释。首先我通过控制器:
@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> <form:form method="GET" action="${pageContext.request.contextPath}/createUser">
<input type="submit" value="Registration">
</form:form>
提交 jsp 时,它会调用用户服务详细信息(在配置类中自动装配)和 transaction 下的方法 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 是自动装配的。
推荐阅读
- python - 如何通过索引列表访问多维数组的元素
- jquery - 我需要从页面加载的下拉列表中动态选择一个选项
- mongodb - MongoDB 基于参考 id 加入用户和点赞集合
- flutter - 更新后缺少 Android Studio 图像资产编辑器
- digital-signature - Signtool.exe /dg /ds /di 选项和时间戳
- algorithm - 如何将json数据转换为html嵌套列表
- python - 使用 OpenCV Python 以与参考图像相同的方向和尺寸转换和显示裁剪图像
- python-3.x - 为什么 int("0xff",16) 计算但 int("hello", 16) 不计算?
- sql - 在 MS Access with VBA 中使用查询转置表
- javascript - 部署到 Heroku 时如何忽略 GitHub 存储库中的文件?