需要的jar包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
<version>3.0.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.3</version>
</dependency>
POJO类
public class Role { //角色类
private int id;
private String name;
private String nameZH;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNameZH() {
return nameZH;
}
public void setNameZH(String nameZH) {
this.nameZH = nameZH;
}
@Override
public String toString() {
return "Role{" +
"id=" + id +
", name='" + name + '\'' +
", nameZH='" + nameZH + '\'' +
'}';
}
}
用户类,实现了UserDetails,并且重写了getAuthorities()方法,来进行权限的设置。
public class User implements UserDetails { //用户类实现了UserDetails
private int id;
private String username;
private String password;
private boolean enable;
private boolean locked;
private List<Role> roles;
//通过该方法自动授予用户权限
public Collection<? extends GrantedAuthority> getAuthorities() {
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
for (Role role : roles) {
System.out.println(role.getName().trim());
authorities.add(new SimpleGrantedAuthority(role.getName()));
}
return authorities;
}
public List<Role> getRoles() {
return roles;
}
public void setRoles(List<Role> roles) {
this.roles = roles;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public String getUsername() {
return null;
}
public boolean isAccountNonExpired() {
return true;
}
public boolean isAccountNonLocked() {
return !locked;
}
public boolean isCredentialsNonExpired() {
return true;
}
public boolean isEnabled() {
return true;
}
public void setPassword(String password) {
this.password = password;
}
public boolean isEnable() {
return enable;
}
public void setEnable(boolean enable) {
this.enable = enable;
}
public boolean isLocked() {
return locked;
}
public void setLocked(boolean locked) {
this.locked = locked;
}
public User(int id, String username, String password) {
this.id = id;
this.username = username;
this.password = password;
}
}
Security主要配置类
package edu.hut.lh.Config;
import edu.hut.lh.Service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
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.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 javax.servlet.http.HttpServlet;
@EnableWebSecurity //开启springsecu
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
UserService service;
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/").permitAll()
.antMatchers("/index.html").hasAuthority("vip1");
.antMatchers("/pageinfo").hasAuthority("vip2");
//设置访问所需的权限
//自定义了登录页
//其中“/login”是没登陆时去访问的请求,也就是可以设置该请求就是去跳转到自定义登录页
//“/Login”是登录页form中action的请求,
//默认定义的登录页input的name是username和password,也可以通过.passwordParameter("password1");自定义
http.formLogin().loginPage("/login").loginProcessingUrl("/Login")
.passwordParameter("password1");
http.csrf().disable();
}
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(service).passwordEncoder(new BCryptPasswordEncoder());
//将service注入
}
@Bean //加密方法
PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
}
Service
登录时,自动获取用户名,通过查询数据库,设置用户的roles属性。然后在实体类中通过getAuthorities()根据roles来进行权限的授予。
package edu.hut.lh.Service;
import edu.hut.lh.Mapper.UserMapper;
import edu.hut.lh.POJO.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
@Service
public class UserService implements org.springframework.security.core.userdetails.UserDetailsService {
@Autowired
UserMapper userMapper;
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userMapper.SelectUserByName(username);
if (user == null){
throw new UsernameNotFoundException("用户不存在");
}
BCryptPasswordEncoder pwdencode= new BCryptPasswordEncoder();
// 设置加密
String encode= pwdencode.encode(user.getPassword().trim());
user.setPassword(encode);
user.setRoles(userMapper.SelectRoleByUid(user.getId()));
return user;
}
}
所使用的表
create table user
(
id int not null, primary key,
name varchar(45) not null,
password varchar(45) not null,
enable int not null,
locked int not null,
perms varchar(50) null
);
create table role_user
(
id int not null,primary key,
r_id int null,
u_id int null,
constraint role_user_id_uindex unique (id)
);
create table role
(
id int not null,primary key,
name varchar(20) null,
nameZH varchar(20) null,
constraint role_id_uindex unique (id)
);
效果展示
首页无须权限
没有登录跳转到登录页
登录页部分代码:其中action和input的name属性在Security配置类中都可以自定义
该用户有VIP1权限进入/index.html成功
没有vip2权限,进入/pageinfo失败,报403错误,也可以自定义错误界面,这里就不演示了。
其中特别要注意的点
这里权限设置中心里是hasRole,我们需要在数据库存储用户角色时,要存为以ROLE_为开头的数据例如RLOE_vip1
当然如果使用的是hasAuthority(),那么就没有这个问题;
// 我是通过hasAuthority()方法去进行授权的,即我数据库角色名称存放的是vip
//而如果我使用hasRole("vip1"),则数据库中存放的是ROLE_vip的形式
http.authorizeRequests().antMatchers("/").permitAll()
.antMatchers("/index.html").hasAuthority("vip1");
.antMatchers("/pageinfo").hasAuthority("vip2");