学习时是看b站狂神说java讲解的springsecurity发现WebSecurityConfigurerAdapter类已经被弃用(2.7.0以下版本可继续使用,2.7.0以上已被启用),于是看官方文档写的一个新版本的配置,新旧对比学习
1.pom依赖
<!-- security-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
1.用户认证和授权
旧版本
@EnableWebSecurity
public class Security extends WebSecurityConfigurerAdapter {
/**
* 授权
* @param http
* @throws Exception
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests()
//首页所有人可以访问,功能也特定人访问
//请求授权的规则
.antMatchers("/").permitAll()
.antMatchers("/level1/**").hasRole("vip1")
.antMatchers("/level2/**").hasRole("vip2")
.antMatchers("/level3/**").hasRole("vip3")
.and()
//无权限默认跳转登录页
.formLogin()
.and()
.build();
//注销,开启注销功能跳转到首页
http
.logout().logoutSuccessUrl("/");
}
/**
* 认证
* @param auth
* @throws Exception
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("lzx")
.password("123456")
.roles("vip1", "vip2")
.and()
.withUser("root")
.password("123456")
.roles("vip1", "vip2", "vip3");
}
}
新版本
@EnableWebSecurity
public class SecurityConfig{
/**
* 授权
* @param http
* @return
* @throws Exception
*/
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
//首页所有人可以访问,功能也特定人访问
//请求授权的规则
return http
.authorizeHttpRequests()
.antMatchers("/").permitAll()
.antMatchers("/level1/**").hasRole("vip1")
.antMatchers("/level2/**").hasRole("vip2")
.antMatchers("/level3/**").hasRole("vip3")
.and()
//无权限默认跳转登录页
.formLogin()
.and()
//注销,开启注销功能,跳转到首页
.logout().logoutSuccessUrl("/")
.and()
.build();
}
/**
* withDefaultPasswordEncoder 被遗弃,原因是不安全,只能在例子中使用
* 不加密码编码使用时会报错 启动时不会报错 passwordEncoder
* 认证例子
* @return
*/
@Bean
public UserDetailsService users() {
//密码加密
PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
//设置用户
UserDetails user = User.builder()
.username("lzx")
.password(encoder.encode("123456"))
//用户权限
.roles("vip1", "vip2")
.build();
UserDetails admin = User.builder()
.username("root")
.password(encoder.encode("123456"))
.roles("vip1", "vip2", "vip3")
.build();
return new InMemoryUserDetailsManager(user, admin);
}
}
2.与thymeleaf集成
2.1pom依赖
<!-- thymeleaf模板-->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-java8time</artifactId>
</dependency>
<!-- thymeleaf集成springsecurity-->
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>
2.2html页面使用
<html lang="en" xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5"
>
2.3sec的使用
2.3.1语法格式
<!--如果未登录-->
<!-- isAuthenticated()判断用户是否登录 -->
<!-- 使用格式 sec:authorize="选择方法" -->
<div sec:authorize="!isAuthenticated()">
<a class="item" th:href="@{/toLogin}">
<i class="address card icon"></i> 登录
</a>
</div>
2.3.2登录账号名称
获取登录用户的名称
用户名:<span sec:authentication="name"></span>
2.3.3principal登录主体(例如我们在配置中设置的lzx与root两个用户的所有信息)
用户名:<span sec:authentication="principal.username"></span>
角色:<span sec:authentication="principal.authorities"></span>
2.3.4权限判断
<div class="column" sec:authorize="hasRole('vip1')">
有vip1权限时显示
</div>
基于数据库的权限配置
在之前的配置中我们设置用户使用的是
@Bean
public UserDetailsService users() {
//密码加密
PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
//设置用户
UserDetails user = User.builder()
.username("lzx")
.password(encoder.encode("123456"))
//用户权限
.roles("vip1", "vip2")
.build();
UserDetails admin = User.builder()
.username("root")
.password(encoder.encode("123456"))
.roles("vip1", "vip2", "vip3")
.build();
return new InMemoryUserDetailsManager(user, admin);
}
如果要将数据库拉进来就不能这样使用了,使用步骤如下
注释掉原来的配置
// @Bean
// public UserDetailsService users() {
//
//
// //密码加密
// PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
// //设置用户
// UserDetails user = User.builder()
// .username("lzx")
// .password(encoder.encode("123456"))
// //用户权限
// .roles("vip1", "vip2")
// .build();
// UserDetails admin = User.builder()
// .username("root")
// .password(encoder.encode("123456"))
// .roles("vip1", "vip2", "vip3")
// .build();
// return new InMemoryUserDetailsManager(user, admin);
// }
定义一个类实现UserDetails接口(用户登录存放的个人信息)必须有用户名密码,需要进行密码比对,权限属性也在这个类中
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import java.util.Collection;
/**
* @author 又菜又爱玩
* @version 1.0
* @date 2022/9/5 9:59
* @blog https://blog.csdn.net/biancheng4/article/details/121727982
*/
@Component
public class AuthUser implements UserDetails {
private String username;
private String password;
private String station;
private Collection<? extends GrantedAuthority> authorities;
public AuthUser() {
}
public AuthUser(String username, String password, String station, Collection<? extends GrantedAuthority> authorities) {
this.username = username;
this.password = password;
this.station = station;
this.authorities = authorities;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return username;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
public String getStation() {
return station;
}
public void setStation(String station) {
this.station = station;
}
@Override
public String toString() {
return "AuthUser{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
", station='" + station + '\'' +
", authorities=" + authorities +
'}';
}
}
实现UserDetailsService方法(自定义逻辑控制认证逻辑)
import com.lzx.springbootsecurity.pojo.security.AuthUser;
import com.lzx.springbootsecurity.pojo.user.Permission;
import com.lzx.springbootsecurity.pojo.user.Role;
import com.lzx.springbootsecurity.pojo.user.User;
import com.lzx.springbootsecurity.service.user.UserService;
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.Component;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
* @author 又菜又爱玩
* @version 1.0
* @date 2022/9/5 10:05
* @blog https://blog.csdn.net/biancheng4/article/details/121727982
*/
@Component
public class UserDetailServiceImpl implements UserDetailsService {
@Resource
private UserService userService;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
System.out.println("username:"+username);
if (username == null){
return null;
}
User userByUsername = userService.findUserByUsername(username);
System.out.println("user:" + userByUsername.toString());
List<GrantedAuthority> list = new ArrayList<>();
Set<Role> roles = userByUsername.getRoles();
for (Role role : roles) {
list.add(new SimpleGrantedAuthority(role.getKeyword()));
Set<Permission> permissionSet = role.getPermissionSet();
for (Permission permission : permissionSet) {
list.add(new SimpleGrantedAuthority(permission.getKeyword()));
}
}
return new AuthUser(username, userByUsername.getPassword(), userByUsername.getStation(), list);
}
}
UserService类实现的主要是去数据库查询用户信息,角色,权限并组合起来
import com.lzx.springbootsecurity.mapper.user.PermissionMapper;
import com.lzx.springbootsecurity.mapper.user.RoleMapper;
import com.lzx.springbootsecurity.mapper.user.UserMapper;
import com.lzx.springbootsecurity.pojo.user.Permission;
import com.lzx.springbootsecurity.pojo.user.Role;
import com.lzx.springbootsecurity.pojo.user.User;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Set;
/**
* @author 又菜又爱玩
* @version 1.0
* @date 2022/9/5 10:28
* @blog https://blog.csdn.net/biancheng4/article/details/121727982
*/
@Service
public class UserService {
@Resource
private UserMapper userMapper;
@Resource
private RoleMapper roleMapper;
@Resource
private PermissionMapper permissionMapper;
public User findUserByUsername(String username){
User byUserName = userMapper.findByUserName(username);
if (byUserName == null){
return null;
}
Integer userId = byUserName.getId();
Set<Role> byUserId = roleMapper.findByUserId(userId);
for (Role role : byUserId) {
Set<Permission> byRoleId = permissionMapper.findByRoleId(role.getId());
role.setPermissionSet(byRoleId);
}
byUserName.setRoles(byUserId);
return byUserName;
}
}
用户类
import com.fasterxml.jackson.annotation.JsonIgnore;
import java.util.Date;
import java.util.Set;
/**
* @author 又菜又爱玩
* @version 1.0
* @date 2022/9/5 10:10
* @blog https://blog.csdn.net/biancheng4/article/details/121727982
*/
public class User {
private Integer id;
private Date birthday;
private String gender;
private String username;
private String password;
private String remark;
private String station;
private String telephone;
@JsonIgnore
private Set<Role> roles;
public Set<Role> getRoles() {
return roles;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
public User() {
}
public User(Integer id, Date birthday, String gender, String username, String password, String remark, String station, String telephone) {
this.id = id;
this.birthday = birthday;
this.gender = gender;
this.username = username;
this.password = password;
this.remark = remark;
this.station = station;
this.telephone = telephone;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
public String getStation() {
return station;
}
public void setStation(String station) {
this.station = station;
}
public String getTelephone() {
return telephone;
}
public void setTelephone(String telephone) {
this.telephone = telephone;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", birthday=" + birthday +
", gender='" + gender + '\'' +
", username='" + username + '\'' +
", password='" + password + '\'' +
", remark='" + remark + '\'' +
", station='" + station + '\'' +
", telephone='" + telephone + '\'' +
", roles=" + roles +
'}';
}
}
角色类
import com.fasterxml.jackson.annotation.JsonIgnore;
import java.util.Set;
/**
* @author 又菜又爱玩
* @version 1.0
* @date 2022/9/5 10:59
* @blog https://blog.csdn.net/biancheng4/article/details/121727982
*/
public class Role {
private Integer id;
private String name;
private String keyword;
private String description;
@JsonIgnore
private Set<Permission> permissionSet;
public Set<Permission> getPermissionSet() {
return permissionSet;
}
public void setPermissionSet(Set<Permission> permissionSet) {
this.permissionSet = permissionSet;
}
public Role() {
}
public Role(Integer id, String name, String keyword, String description) {
this.id = id;
this.name = name;
this.keyword = keyword;
this.description = description;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getKeyword() {
return keyword;
}
public void setKeyword(String keyword) {
this.keyword = keyword;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
权限类
/**
* @author 又菜又爱玩
* @version 1.0
* @date 2022/9/5 13:55
* @blog https://blog.csdn.net/biancheng4/article/details/121727982
*/
public class Permission {
private Integer id;
private String name;
private String keyword;
private String description;
public Permission() {
}
public Permission(Integer id, String name, String keyword, String description) {
this.id = id;
this.name = name;
this.keyword = keyword;
this.description = description;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getKeyword() {
return keyword;
}
public void setKeyword(String keyword) {
this.keyword = keyword;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
注解权限
在配置文件中加上
@EnableGlobalMethodSecurity(prePostEnabled = true)
开启注解
注解的使用
@PreAuthorize("hasAuthority('vip2')")
@RequestMapping("/level3/{id}")
public String toLevel3(@PathVariable("id") int id){
return "views/level3/" + id;
}
<div class="column" sec:authorize="hasAuthority('SETMEAL_EDIT')">
<div class="ui raised segment">
<div class="ui">
<div class="content">
<h5 class="content">Level 3</h5>
<hr>
<div><a th:href="@{/level3/1}"><i class="bullhorn icon"></i> Level-3-1</a></div>
<div><a th:href="@{/level3/2}"><i class="bullhorn icon"></i> Level-3-2</a></div>
<div><a th:href="@{/level3/3}"><i class="bullhorn icon"></i> Level-3-3</a></div>
</div>
</div>
</div>
</div>
<button sec:authorize="hasRole('ADMIN')">新增</button>
<button sec:authorize="hasAuthority('USER_DELETE')">删除</button>
<button sec:authorize="hasAuthority('ROLE_EDIT')">修改</button>
springSecurity 文档官网:点此跳转
------------------------------ 还在学习中持续更新 ----------------------------------