我有一个基于 Spring MVC + Hibrnate 的完整工作的 CRUD 应用程序,我正在尝试将 spring Security 集成到其中,但我遇到了错误。尝试了几种不同的方法,但仍然没有。
错误
org.springframework.beans.factory.UnsatisfiedDependencyException:创建文件 [C:\Users\Administrator\Desktop\Spring-Security\target\Spring-Security\WEB-INF\classes\com\ 中定义的名称为“roleDaoImp”的 bean 时出错spring\dao\RoleDaoImp.class]:通过构造函数参数0表示的不满足依赖;嵌套异常是 org.springframework.beans.factory.NoSuchBeanDefinitionException:没有可用的“javax.persistence.EntityManager”类型的合格 bean:预计至少有 1 个有资格作为自动装配候选者的 bean。依赖注释:{}
我将跳过具有休眠配置的类、具有应用程序初始化的类和 LoginSuccessHandler,因为那里一切都很好。我还将跳过带有与用户实体相关的代码的服务和类。
问题出在角色的本质上,所以我在下面给出代码。如果更简单,那么链接到github
所以,应用程序配置 WebConfig.java
package com.spring.config;
//куча импортов
@Configuration
@EnableWebMvc
@ComponentScan("com.spring")
public class WebConfig implements WebMvcConfigurer {
private final ApplicationContext applicationContext;
public WebConfig(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Bean
public SpringResourceTemplateResolver templateResolver() {
SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
templateResolver.setApplicationContext(applicationContext);
templateResolver.setPrefix("/WEB-INF/pages/");
templateResolver.setSuffix(".html");
return templateResolver;
}
@Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver());
templateEngine.setEnableSpringELCompiler(true);
return templateEngine;
}
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(templateEngine());
registry.viewResolver(resolver);
}
}
SpringSecurityInitializer.java
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
public class SpringSecurityInitializer extends AbstractSecurityWebApplicationInitializer {
}
安全配置.java
//куча импортов
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("ADMIN").password("ADMIN").roles("ADMIN")
.and()
.withUser("USER").password("USER").roles("USER")
.and()
.withUser("EDITOR").password("EDITOR").roles("EDITOR");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin()
// указываем страницу с формой логина
.loginPage("/login")
//указываем логику обработки при логине
.successHandler(new LoginSuccessHandler())
// указываем action с формы логина
.loginProcessingUrl("/login")
// Указываем параметры логина и пароля с формы логина
.usernameParameter("j_username")
.passwordParameter("j_password")
// даем доступ к форме логина всем
.permitAll();
http
.logout()
// разрешаем делать логаут всем
.permitAll()
// указываем URL логаута
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
// указываем URL при удачном логауте
.logoutSuccessUrl("/index?logout")
//выклчаем кроссдоменную секьюрность (на этапе обучения неважна)
.and().csrf().disable();
http
// делаем страницу регистрации недоступной для авторизированных пользователей
.authorizeRequests()
//страницы аутентификаци доступна всем
.antMatchers("/login", "/").anonymous()
// защищенные URL
.antMatchers("/users/**").access("hasAnyRole('ROLE_ADMIN', 'ROLE_USER', 'ROLE_EDITOR')")
.antMatchers("/user/**").access("hasAnyRole('ROLE_ADMIN', 'ROLE_USER', 'ROLE_EDITOR')")
.antMatchers("/admin/**").access("hasAnyRole('ROLE_ADMIN')")
.antMatchers("/editor/**").access("hasAnyRole('ROLE_EDITOR', 'ROLE_ADMIN')")
.anyRequest().authenticated();
}
@Bean
public PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
}
我将跳过具有休眠配置的类、具有应用程序初始化的类和 LoginSuccessHandler,因为那里一切都很好。
我还将跳过与用户实体相关的代码,那里的一切似乎也都很好。
问题出在角色的本质上,所以我在下面给出代码。
角色.java
@Entity
@Table(name = "users")
public class Role {
@Id
@GeneratedValue
private Integer id;
private String role;
@OneToMany(cascade=CascadeType.ALL)
@JoinTable(name="user_roles",
joinColumns = {@JoinColumn(name="role_id", referencedColumnName="id")},
inverseJoinColumns = {@JoinColumn(name="user_id", referencedColumnName="id")}
)
private List<User> userRoles;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
public List<User> getUserRoles() {
return userRoles;
}
public void setUserRoles(List<User> userRoles) {
this.userRoles = userRoles;
}
}
RoleDao.java
public interface RoleDao {
Role getRole(int id);
}
RoleDaoImp.java
@Component
@Repository
public class RoleDaoImp implements RoleDao {
private final EntityManager entityManager;
public RoleDaoImp(EntityManager entityManager) {
this.entityManager = entityManager;
}
public Role getRole(int id) {
return entityManager.find(Role.class, id);
}
}
CustomUserDetailsService.java
@Service
@Transactional(readOnly=true)
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private UserDao userDao;
public User loadUserByUsername(String login)
throws UsernameNotFoundException {
com.spring.model.User domainUser = userDao.getUserByLogin(login);
return new User(
domainUser.getLogin(),
domainUser.getPassword(),
true,
true,
true,
true,
getAuthorities(domainUser.getRole().getId())
);
}
public Collection<? extends GrantedAuthority> getAuthorities(Integer role) {
return getGrantedAuthorities(getRoles(role));
}
public List<String> getRoles(Integer role) {
List<String> roles = new ArrayList<String>();
if (role == 1) {
roles.add("ROLE_EDITOR");
roles.add("ROLE_ADMIN");
} else if (role == 2) {
roles.add("ROLE_EDITOR");
}
return roles;
}
public static List<GrantedAuthority> getGrantedAuthorities(List<String> roles) {
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
for (String role : roles) {
authorities.add(new SimpleGrantedAuthority(role));
}
return authorities;
}
}
胸口刚刚打开……问题的答案——我忘了把@PersistenceContext 放在RoleDaoImp 中,而是初始化了构造函数,想法对它没有任何反应……
问题已基本解决。
但如果有什么要通过代码添加的,我会很高兴的。