我具有配置有ManytoMany关系的用户,角色和特权表。安全配置针对数据库验证用户凭据,并检查用户角色以访问URL。由于角色和用户通过“多对多”关系加入,因此我在子级添加了@JsonIgnore
注释,以防止StackOverflow错误。
@JsonIgnore
@ManyToMany(mappedBy = "roles")
private Collection<User> users;
在父端,我配置了连接表和连接列
@ManyToMany
@JoinTable(
name = "user_role",
joinColumns = @JoinColumn(name = "user_id",referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(name = "role_id",referencedColumnName = "id")
)
private Collection<Role> roles;
当用户尝试登录时,我看到一个错误方法抛出了“ java.lang.StackOverflowError”异常。无法评估com.springtesting.model.User.toString()。 JsonIgnore应该防止这种无限递归,而且我不确定为什么它没有这样做。
User.Java
package com.springtesting.model;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import lombok.Data;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Collection;
@Entity
@Data
@Table(name = "user")
public class User implements Serializable
{
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@Column(name = "username")
private String username;
@Column(name = "active")
private Boolean active;
@Column(name = "password", nullable = false)
private String password;
@OneToOne(cascade = CascadeType.ALL, mappedBy = "user")
@JoinColumn(name = "user_profile_id")
private UserProfile userProfile;
@ManyToMany
@JoinTable(
name = "user_role",
joinColumns = @JoinColumn(name = "user_id",referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(name = "role_id",referencedColumnName = "id")
)
private Collection<Role> roles;
public User()
{
}
public User(String username, String password, Boolean active, UserProfile userProfile)
{
this.username = username;
this.password = password;
this.active = active;
this.userProfile = userProfile;
}
}
Role.Java
package com.springtesting.model;
import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import lombok.Data;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Collection;
@Entity
@Data
@Table(name = "role")
public class Role implements Serializable
{
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@Column(name = "name",nullable = false)
private String name;
@JsonIgnore
@ManyToMany(mappedBy = "roles")
private Collection<User> users;
@ManyToMany
@JoinTable(
name = "role_privilege",
joinColumns = @JoinColumn(name = "role_id",referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(name = "privilege_id",referencedColumnName = "id")
)
private Collection<Privilege> privileges;
}
Privilege.Java
package com.springtesting.model;
import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Collection;
@Entity
@Data
@Table(name = "privilege")
public class Privilege implements Serializable
{
private static final long serialVersionUID = 3L;
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@JsonIgnore
@ManyToMany(mappedBy = "privileges")
private Collection<Role> roles;
}
SecurityConfig.Java
package com.springtesting.security.config;
import com.springtesting.security.MyUserDetailsService;
import com.springtesting.security.handlers.CustomAuthenticationFailureHandler;
import com.springtesting.security.handlers.CustomAuthenticationSuccessHandler;
import com.springtesting.security.handlers.CustomLogoutSuccessHandler;
import com.springtesting.security.providers.CustomDaoAuthenticationProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.session.HttpSessionEventPublisher;
import org.springframework.session.FindByIndexNameSessionRepository;
import org.springframework.session.Session;
import org.springframework.session.jdbc.config.annotation.web.http.EnableJdbcHttpSession;
import org.springframework.session.security.SpringSessionBackedSessionRegistry;
import org.springframework.session.security.web.authentication.SpringSessionRememberMeServices;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
private final MyUserDetailsService userDetailsService;
/*@Autowired
private final FindByIndexNameSessionRepository<Session> sessionRepository = null;*/
@Autowired
public SecurityConfig(MyUserDetailsService userDetailsService)
{
this.userDetailsService = userDetailsService;
}
@Override
public void configure(AuthenticationManagerBuilder auth)
{
auth.authenticationProvider(getDaoAuthenticationProvider());
}
@Bean
public CustomDaoAuthenticationProvider getDaoAuthenticationProvider()
{
CustomDaoAuthenticationProvider daoAuthenticationProvider=new CustomDaoAuthenticationProvider();
daoAuthenticationProvider.setUserDetailsService(userDetailsService);
daoAuthenticationProvider.setPasswordEncoder(getBCryptPasswordEncoder());
return daoAuthenticationProvider;
}
/* BCrypt strength should 12 or more*/
@Bean
public PasswordEncoder getBCryptPasswordEncoder()
{
return new BCryptPasswordEncoder(12);
}
@Override
protected void configure(HttpSecurity http) throws Exception
{
http.authorizeRequests()
.antMatchers("/anonymous*").anonymous()
.antMatchers("/users/**").hasAuthority(AuthorityConstants.Admin)
.antMatchers("/admin**").hasAuthority(AuthorityConstants.Admin)
.antMatchers("/profile/**").hasAuthority(AuthorityConstants.User)
.antMatchers("/api/**").hasAuthority(AuthorityConstants.ApiUser)
.antMatchers("/dba/**").hasAuthority(AuthorityConstants.Dba)
.anyRequest().authenticated()
.and()
.httpBasic()
.and()
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/login")
.successHandler(new CustomAuthenticationSuccessHandler())
.failureHandler(new CustomAuthenticationFailureHandler())
.permitAll()
.and()
.logout()
.deleteCookies("JSESSIONID")
.logoutSuccessHandler(new CustomLogoutSuccessHandler())
.permitAll()
.and()
.rememberMe().rememberMeServices(springSessionRememberMeServices());
http.sessionManagement()
.invalidSessionUrl("/invalidSession.html")
.sessionFixation()
.migrateSession()
.maximumSessions(1);
//.sessionRegistry(sessionRegistry());;
}
@Bean
public SpringSessionRememberMeServices springSessionRememberMeServices()
{
SpringSessionRememberMeServices rememberMeServices = new SpringSessionRememberMeServices();
// optionally customize
rememberMeServices.setRememberMeParameterName("remember-me");
rememberMeServices.setValiditySeconds(86000);
return rememberMeServices;
}
/* @Bean
SpringSessionBackedSessionRegistry sessionRegistry()
{
return new SpringSessionBackedSessionRegistry<>(this.sessionRepository);
}*/
@Override
public void configure(WebSecurity web) throws Exception
{
web
.ignoring()
.antMatchers("/resources/**", "/static/**", "/css/**", "/js/**", "/images/**");
}
@Bean
public HttpSessionEventPublisher httpSessionEventPublisher()
{
return new HttpSessionEventPublisher();
}
@Bean("authenticationManager")
@Override
public AuthenticationManager authenticationManagerBean() throws Exception
{
return super.authenticationManagerBean();
}
}
MyUserDetailsService.java
package com.springtesting.security;
import com.springtesting.model.Privilege;
import com.springtesting.model.Role;
import com.springtesting.model.User;
import com.springtesting.repo.RoleRepository;
import com.springtesting.repo.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import javax.transaction.Transactional;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@Service
@Transactional
public class MyUserDetailsService implements UserDetailsService
{
private UserRepository userRepository;
private final RoleRepository roleRepository;
@Autowired
public MyUserDetailsService(UserRepository userRepository, RoleRepository roleRepository)
{
this.userRepository=userRepository;
this.roleRepository = roleRepository;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
{
User user=userRepository.findByUsername(username);
if(user == null)
throw new UsernameNotFoundException("Could not find Username");
return new MyUserPrincipal(user,getGrantedAuthorities(user.getRoles()));
}
private List<GrantedAuthority> getGrantedAuthorities(Collection<Role> roles)
{
List<GrantedAuthority> authorities = new ArrayList<>();
for (Role role : roles)
{
authorities.add(new SimpleGrantedAuthority(role.getName()));
}
return authorities;
}
/* private List<GrantedAuthority> getGrantedAuthorities(Collection<String> privileges)
{
List<GrantedAuthority> authorities = new ArrayList<>();
for (String privilege : privileges)
{
authorities.add(new SimpleGrantedAuthority(privilege));
}
return authorities;
}
private List<? extends GrantedAuthority> getAuthorities(Collection<Role> roles)
{
return getGrantedAuthorities(getPrivileges(roles));
}
private List<String> getPrivileges(Collection<Role> roles)
{
List<String> privileges = new ArrayList<>();
List<Privilege> collection = new ArrayList<>();
for (Role role : roles)
{
collection.addAll(role.getPrivileges());
}
for (Privilege item : collection)
{
privileges.add(item.getName());
}
return privileges;
}
*/
}
答案 0 :(得分:0)
我发现了问题。当我将Lombok用于getter,setter和toString()方法时,它会尝试遍历子表中显示的角色/用户,从而导致无限递归。覆盖new_df = pd.DataFrame(list(df['my_funky_column'].apply(str.split)), columns=['column1', 'column2', 'column3', 'column4'])
默认实现解决了我的问题