如何在 Spring Boot 中实现基于角色权限的系统
Posted
技术标签:
【中文标题】如何在 Spring Boot 中实现基于角色权限的系统【英文标题】:How to implement Role Permission based system in Spring Boot 【发布时间】:2016-11-09 19:14:30 【问题描述】:我正在尝试使用 spring boot 和 spring security 来实现基于角色权限的系统。为此,我以http://www.baeldung.com/role-and-privilege-for-spring-security-registration 为例 ,但没能做到。
努力
SpringSecurity 配置
package com.insight;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
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.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private AuthenticationSuccessHandler myAuthenticationSuccessHandler;
@Autowired
private LogoutSuccessHandler myLogoutSuccessHandler;
@Autowired
private AuthenticationFailureHandler authenticationFailureHandler;
@Override
protected void configure(final AuthenticationManagerBuilder auth) throws Exception
auth.authenticationProvider(authProvider());
@Override
public void configure(final WebSecurity web) throws Exception
web.ignoring().antMatchers("/resources/**");
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception
httpSecurity.authorizeRequests()
.antMatchers("/js/**","/css/**","/images/**","/fonts/**").permitAll()
.antMatchers("/user/signup/**","/about", "/","/user/login/").permitAll() // #4
.anyRequest().authenticated() // 7
.and()
.formLogin().failureUrl("/user/login?error=true")
.defaultSuccessUrl("/")
.loginProcessingUrl("/user/validateLogin")
.usernameParameter("email")
.passwordParameter("password")
.loginPage("/user/login")
.permitAll()
.and()
.logout().logoutRequestMatcher(new AntPathRequestMatcher("/user/logout")).logoutSuccessUrl("/user/login")
.permitAll();
@Bean
public DaoAuthenticationProvider authProvider()
final DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(userDetailsService);
authProvider.setPasswordEncoder(encoder());
return authProvider;
@Bean
public PasswordEncoder encoder()
return new BCryptPasswordEncoder(11);
用户模型
package com.insight.models;
import java.util.Collection;
import java.util.Date;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.PrePersist;
import javax.persistence.PreUpdate;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;
import org.hibernate.validator.constraints.Email;
@Entity
@Table(name = "users")
public class User
// An autogenerated id (unique for each user in the db)
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
private Set<Address> addresses;
@NotNull
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "title")
private Configuration title;
@OneToOne(cascade=CascadeType.ALL)
@JoinTable(name="user_roles",
joinColumns = @JoinColumn(name="user_id", referencedColumnName="id"),
inverseJoinColumns = @JoinColumn(name="role_id", referencedColumnName="id")
)
private Collection<Role> roles;
@NotNull
private String firstName;
@NotNull
private String lastName;
@NotNull
@Column(unique = true)
@Email
private String email;
@NotNull
private String password;
private String profileImage;
@Column(name = "created_at")
private Date createdAt;
@Column(name = "created_by")
private String createdBy;
@Column(name = "updated_at")
private Date updatedAt;
@Column(name = "updated_by")
private String updatedBy;
private String status;
private String deleteFlag;
private String confirmationCode;
private String lastLoginAt;
private boolean enabled;
private boolean tokenExpired;
public User()
super();
this.enabled = false;
@PrePersist
void createdAt()
this.createdAt = this.updatedAt = new Date();
@PreUpdate
void updatedAt()
this.updatedAt = new Date();
public Long getId()
return id;
public void setId(Long id)
this.id = id;
public Set<Address> getAddresses()
return addresses;
public void setAddresses(Set<Address> addresses)
this.addresses = addresses;
public Configuration getTitle()
return title;
public void setTitle(Configuration title)
this.title = title;
public Collection<Role> getRoles()
return roles;
public void setRoles(Collection<Role> roles)
this.roles = roles;
public String getFirstName()
return firstName;
public void setFirstName(String firstName)
this.firstName = firstName;
public String getLastName()
return lastName;
public void setLastName(String lastName)
this.lastName = lastName;
public String getEmail()
return email;
public void setEmail(String email)
this.email = email;
public String getPassword()
return password;
public void setPassword(String password)
this.password = password;
public String getProfileImage()
return profileImage;
public void setProfileImage(String profileImage)
this.profileImage = profileImage;
public Date getCreatedAt()
return createdAt;
public void setCreatedAt(Date createdAt)
this.createdAt = createdAt;
public String getCreatedBy()
return createdBy;
public void setCreatedBy(String createdBy)
this.createdBy = createdBy;
public Date getUpdatedAt()
return updatedAt;
public void setUpdatedAt(Date updatedAt)
this.updatedAt = updatedAt;
public String getUpdatedBy()
return updatedBy;
public void setUpdatedBy(String updatedBy)
this.updatedBy = updatedBy;
public String getStatus()
return status;
public void setStatus(String status)
this.status = status;
public String getDeleteFlag()
return deleteFlag;
public void setDeleteFlag(String deleteFlag)
this.deleteFlag = deleteFlag;
public String getConfirmationCode()
return confirmationCode;
public void setConfirmationCode(String confirmationCode)
this.confirmationCode = confirmationCode;
public String getLastLoginAt()
return lastLoginAt;
public void setLastLoginAt(String lastLoginAt)
this.lastLoginAt = lastLoginAt;
public boolean isEnabled()
return enabled;
public void setEnabled(boolean enabled)
this.enabled = enabled;
public boolean isTokenExpired()
return tokenExpired;
public void setTokenExpired(boolean tokenExpired)
this.tokenExpired = tokenExpired;
@Override
public int hashCode()
final int prime = 31;
int result = 1;
result = (prime * result) + ((email == null) ? 0 : email.hashCode());
return result;
@Override
public boolean equals(final Object obj)
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final User user = (User) obj;
if (!email.equals(user.email))
return false;
return true;
@Override
public String toString()
final StringBuilder builder = new StringBuilder();
builder.append("User [firstName=").append(firstName).append("]").append("[lastName=").append(lastName).append("]").append("[username").append(email).append("]");
return builder.toString();
榜样
package com.insight.models;
import java.util.Collection;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
@Entity
@Table(name="roles")
public class Role
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
@ManyToMany(mappedBy = "roles")
private Collection<User> userRoles;
@ManyToMany
@JoinTable(
name = "roles_privileges",
joinColumns = @JoinColumn(name = "role_id", referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(name = "permission_id", referencedColumnName = "id"))
private Collection<Permission> permissions;
public Role(String name)
this.name=name;
public Long getId()
return id;
public void setId(Long id)
this.id = id;
public String getName()
return name;
public void setName(String name)
this.name = name;
public Collection<User> getUserRoles()
return userRoles;
public void setUserRoles(Collection<User> userRoles)
this.userRoles = userRoles;
public Collection<Permission> getPermissions()
return permissions;
public void setPermissions(Collection<Permission> permissions)
this.permissions = permissions;
@Override
public int hashCode()
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
@Override
public boolean equals(final Object obj)
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final Role role = (Role) obj;
if (!role.equals(role.name))
return false;
return true;
@Override
public String toString()
final StringBuilder builder = new StringBuilder();
builder.append("Role [name=").append(name).append("]").append("[id=").append(id).append("]");
return builder.toString();
权限模型
package com.insight.models;
import java.util.Collection;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
public class Permission
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
@ManyToMany(mappedBy = "permissions")
private Collection<Role> roles;
public Permission(String name2)
name = name;
public Long getId()
return id;
public void setId(Long id)
this.id = id;
public String getName()
return name;
public void setName(String name)
this.name = name;
public Collection<Role> getRoles()
return roles;
public void setRoles(Collection<Role> roles)
this.roles = roles;
@Override
public int hashCode()
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
@Override
public boolean equals(Object obj)
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Permission other = (Permission) obj;
if (name == null)
if (other.name != null)
return false;
else if (!name.equals(other.name))
return false;
return true;
@Override
public String toString()
final StringBuilder builder = new StringBuilder();
builder.append("Permission [name=").append(name).append("]").append("[id=").append(id).append("]");
return builder.toString();
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.insight</groupId>
<artifactId>insight</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>insight</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity4</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
<version>1.3.6.RELEASE</version><!--$NO-MVN-MAN-VER$-->
</dependency>
<dependency>
<groupId>org.passay</groupId>
<artifactId>passay</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
CustomUserDetailsService
package com.insight.services;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
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 org.springframework.transaction.annotation.Transactional;
import com.insight.models.Permission;
import com.insight.models.Role;
import com.insight.models.User;
import com.insight.repositories.RoleRepository;
import com.insight.repositories.UserRepository;
@Service("userDetailsService")
@Transactional
public class CustomUserDetailsService implements UserDetailsService
@Autowired
private UserRepository userRepository;
@Autowired
private IUserService service;
@Autowired
private MessageSource messages;
@Autowired
private RoleRepository roleRepository;
@Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException
User user = userRepository.findByEmail(email);
if (user == null)
return new org.springframework.security.core.userdetails.User(
" ", " ", true, true, true, true,
getAuthorities(Arrays.asList(roleRepository.findByName("ROLE_USER"))));
return new org.springframework.security.core.userdetails.User(
user.getEmail(), user.getPassword(), user.isEnabled(), true, true,
true, getAuthorities(user.getRoles()));
private Collection<? extends GrantedAuthority> getAuthorities(Collection<Role> roles)
return getGrantedAuthorities(getPrivileges(roles));
private List<String> getPrivileges(Collection<Role> roles)
List<String> privileges = new ArrayList<String>();
List<Permission> collection = new ArrayList<Permission>();
for (Role role : roles)
collection.addAll(role.getPermissions());
for (Permission item : collection)
privileges.add(item.getName());
return privileges;
private List<GrantedAuthority> getGrantedAuthorities(List<String> privileges)
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
for (String privilege : privileges)
authorities.add(new SimpleGrantedAuthority(privilege));
return authorities;
那里也有一些其他的课程,但由于篇幅较大,我没有发布,如果有人需要详细信息,我会发布。
当我尝试运行时,我在控制台上收到以下错误:
org.springframework.beans.factory.BeanCreationException:创建名为“org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration”的bean时出错:注入自动装配的依赖项失败;嵌套异常是 org.springframework.beans.factory.BeanCreationException:无法自动装配方法:public void org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration.setFilterChainProxySecurityConfigurer(org.springframework.security.config.annotation.ObjectPostProcessor, java.util.List) 抛出 java.lang.Exception;嵌套异常是 org.springframework.beans.factory.BeanExpressionException:表达式解析失败;嵌套异常是 org.springframework.beans.factory.BeanCreationException:创建名为“securityConfiguration”的 bean 时出错:注入自动装配的依赖项失败;嵌套异常是 org.springframework.beans.factory.BeanCreationException:无法自动装配字段:私有 org.springframework.security.core.userdetails.UserDetailsService com.insight.SecurityConfiguration.userDetailsService;嵌套异常是 org.springframework.beans.factory.BeanCreationException:创建名为“userDetailsService”的 bean 时出错:注入自动装配的依赖项失败;嵌套异常是 org.springframework.beans.factory.BeanCreationException:无法自动装配字段:私有 com.insight.repositories.UserRepository com.insight.services.CustomUserDetailsService.userRepository;嵌套异常是 org.springframework.beans.factory.BeanCreationException:创建名称为“userRepository”的 bean 时出错:设置 bean 时无法创建类型为 [org.springframework.orm.jpa.SharedEntityManagerCreator] 的内部 bean '(inner bean)#778bd3a2'属性“实体管理器”;嵌套异常是 org.springframework.beans.factory.BeanCreationException:创建名称为“(内部 bean)#778bd3a2”的 bean 时出错:设置构造函数参数时无法解析对 bean 'entityManagerFactory' 的引用;嵌套异常是 org.springframework.beans.factory.BeanCreationException:在类路径资源 [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.class] 中定义名称为“entityManagerFactory”的 bean 创建错误:调用 init 方法失败;嵌套异常是 javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory 在 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] 在 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] 在 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] 在 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] 在 org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] 在 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] 在 org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] 在 org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] 在 org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:368) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] 在
请朋友们帮帮我。
【问题讨论】:
尝试用@EnableWebSecurity 为你的SecurityConfiguration.class 和用@Component 为你的CustomUserDetailsService.class 注释。 您的数据库是否已设置并正在运行?这个错误“Error creation bean with name 'entityManagerFactory'”通常意味着数据库连接有问题。 @Mandy 你找到解决方案了吗? 【参考方案1】:正如 Michal 指出的,这是一个数据库问题 -
在类路径资源 [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.class] 中定义名称为“entityManagerFactory”的 bean 创建错误: 调用 init 方法失败;嵌套异常是 javax.persistence.PersistenceException: [PersistenceUnit:默认] 无法在 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues 构建 Hibernate SessionFactory(AutowiredAnnotationBeanPostProcessor.java:334)你的 MySQL 数据库可能没有运行,或者你可能没有在 spring 属性中提供数据源连接 [我看到你有一个 MySQL 依赖引用]
对于调试或测试用例,您可以尝试 H2 -
<!-- https://mvnrepository.com/artifact/com.h2database/h2 -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.200</version>
<scope>test</scope>
</dependency>
【讨论】:
【参考方案2】:用@EnableWebSecurity
注释你的SecurityConfiguration
【讨论】:
以上是关于如何在 Spring Boot 中实现基于角色权限的系统的主要内容,如果未能解决你的问题,请参考以下文章