Spring Security授权案例集合
目录
授权
前置内容
描述:授权是指认证通过后,系统赋予用户一定的权限,而用户能根据此权限,访问系统中的某些资源
授权方式:RBAC
基于角色的访问控制(一般不用)
直接给某个角色赋予访问权限
角色A有权利访问资源a,但当A发生变化时,则需要进行修改
基于资源的访问控制(常用)
根据角色拥有的资源权限,赋予额外的资源权限
角色A有权利访问资源a
+
访问资源a的所有角色有权利访问资源b
---->>
角色A可以访问资源b
权限表的设计
用户与权限的关系:多对多
原则设计:设计中间表,降低范式化程度
用户、角色、权限:
如果只有用户和权限两表,操作量会非常大,因此增加角色表和两个中间表,保证低范式。
建表和相关说明
表说明
权限
角色
角色权限关系表
用户
用户角色关系表
建表代码
CREATE TABLE `users` (
`uid` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`phone` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`uid`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
INSERT INTO `users` VALUES (1, 'baizhan', '$2a$10$Eqv9PRMl6bPt5BiwgPr2eucgyl.E.xLENt4bvfDvv7DyS5AVPT.U6', '13812345678');
CREATE TABLE `role` (
`rid` int(11) NOT NULL AUTO_INCREMENT,
`roleName` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`roleDesc` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`rid`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
INSERT INTO `role` VALUES (1, '总经理', '管理整个公司');
INSERT INTO `role` VALUES (2, '股东', '参与公司决策');
INSERT INTO `role` VALUES (3, '财务', '管理公司资产');
CREATE TABLE `permission` (
`pid` int(11) NOT NULL AUTO_INCREMENT,
`permissionName` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`pid`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
INSERT INTO `permission` VALUES (1, '查询报表', '/reportform/find');
INSERT INTO `permission` VALUES (2, '查询工资', '/salary/find');
INSERT INTO `permission` VALUES (3, '查询税务', '/tax/find');
CREATE TABLE `users_role` (
`uid` int(255) NOT NULL,
`rid` int(11) NOT NULL,
PRIMARY KEY (`uid`, `rid`) USING BTREE,
INDEX `rid`(`rid`) USING BTREE,
CONSTRAINT `users_role_ibfk_1` FOREIGN KEY (`uid`) REFERENCES `users` (`uid`) ON DELETE RESTRICT ON UPDATE RESTRICT,
CONSTRAINT `users_role_ibfk_2` FOREIGN KEY (`rid`) REFERENCES `role` (`rid`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
INSERT INTO `users_role` VALUES (1, 2);
INSERT INTO `users_role` VALUES (1, 3);
CREATE TABLE `role_permission` (
`rid` int(11) NOT NULL,
`pid` int(11) NOT NULL,
PRIMARY KEY (`rid`, `pid`) USING BTREE,
INDEX `pid`(`pid`) USING BTREE,
CONSTRAINT `role_permission_ibfk_1` FOREIGN KEY (`rid`) REFERENCES `role` (`rid`) ON DELETE RESTRICT ON UPDATE RESTRICT,
CONSTRAINT `role_permission_ibfk_2` FOREIGN KEY (`pid`) REFERENCES `permission` (`pid`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
INSERT INTO `role_permission` VALUES (1, 1);
INSERT INTO `role_permission` VALUES (2, 1);
INSERT INTO `role_permission` VALUES (1, 2);
INSERT INTO `role_permission` VALUES (3, 2);
INSERT INTO `role_permission` VALUES (1, 3);
INSERT INTO `role_permission` VALUES (2, 3);
用户权限配置
内部关键类GrantedAuthority和SimpleGrantedAuthority
描述:GrantedAuthority是security内部中的权限接口,SimpleGrantedAuthority是前者的一个简单实现。
使用说明:
创建GrantedAuthority列表存储所有的用户权限,存入的是SimpleGrantedAuthority的实例,SimpleGrantedAuthority每个实例在创建时,需要写入权限信息(String类型),写入方式一般为自己创建的权限实体类
关键类使用示例
List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
for (Permission permission : permissions) {
grantedAuthorities.add(new SimpleGrantedAuthority(permission.getUrl()));
}
用户权限配置完整代码
此类的作用是负责处理用户、权限和数据库部分的交互逻辑
内部只定义了一个方法,用于根据给定用户名,加载用户信息(包含权限内容),用于进行授权
根据用户名加载一个用户时,会从数据库中读取这个用户的相应权限和其他信息,同时这些信息被写入到这个用户实例上,完成了授权操作
package com.wunaiieq.tmp2024121105.service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wunaiieq.tmp2024121105.entity.Permission;
import com.wunaiieq.tmp2024121105.entity.Users;
import com.wunaiieq.tmp2024121105.mapper.UsersMapper;
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.User;
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 java.util.ArrayList;
import java.util.List;
@Service
public class MyUserDetailService implements UserDetailsService {
@Autowired
private UsersMapper usersMapper;
//自定义认证逻辑
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//1.查询条件
QueryWrapper<Users> wrapper = new QueryWrapper<Users>().eq("username", username);
//2.查询用户
Users users = usersMapper.selectOne(wrapper);
if (users == null){
return null;
}
//3.查询用户权限,用我们自定义的Permission类去接收,捕获成一个列表
List<Permission> permissions = usersMapper.findPermissionByUsername(username);
//4.将自定义的权限集合转换为security规定的权限集合
List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
for (Permission permission : permissions) {
grantedAuthorities.add(//将实例添加到grantedAuthorities集合中
new SimpleGrantedAuthority(//将下面获取到的权限(字符串形式)创建出SimpleGrantedAuthority的示例
permission.getUrl()//调用列表中每个Permission对象的getUrl()方法,获取权限
)
);
}
//5.封装为UserDetails对象
UserDetails userDetails = User.withUsername(users.getUsername())
.password(users.getPassword())
.authorities(grantedAuthorities)
.build();
//4.返回封装好的UserDetails对象
return userDetails;
}
}
资源访问控制
方法一、配置类设置访问控制
controller
controller层中设置对应的url,作为资源
@GetMapping("/reportform/find")
public String findReportForm() {
return "查询报表";
}
@GetMapping("/salary/find")
public String findSalary() {
return "查询工资";
}
@GetMapping("/staff/find")
public String findStaff() {
return "查询员工";
}
示例
在配置类中修改如下
httpSecurity.authorizeHttpRequests(
resp -> {
resp.requestMatchers(new AntPathRequestMatcher("/login.html"), new AntPathRequestMatcher("/fail,html")).permitAll(); // 不需要认证的资源
resp.requestMatchers(new AntPathRequestMatcher("/staff/find")).hasAnyAuthority("/staff/find");
resp.anyRequest().authenticated();//其余所有请求都需要认证
}
);
以资源去匹配权限
资源过多时,用此方法,在访问资源时,判断用户是否具有访问此url的权限
在SecurityConfigure中进行修改
httpSecurity.authorizeHttpRequests(resp -> {
resp.requestMatchers(new AntPathRequestMatcher("/login.html"), new AntPathRequestMatcher("/fail.html")).permitAll(); // 不需要认证的资源
resp.requestMatchers(new AntPathRequestMatcher("/css/*.css"), new AntPathRequestMatcher("/js/*.js"), new AntPathRequestMatcher("/img/**")).permitAll(); // 静态资源不需要认证
/**
* access的参数是一个函数式接口
* 方法的第一个参数代表认证对象,可以获取认证用户的权限集合
* 方法的第二个参数代表网络环境,可以获取当前请求的路径
*/
resp.anyRequest().access(
(authentication, requestContext) -> {
// 获取认证的用户权限
Collection<? extends GrantedAuthority> authorities = authentication.get().getAuthorities();
// 获取请求的URL路径
String uri = requestContext.getRequest().getRequestURI();
// 将URL路径封装为权限对象
SimpleGrantedAuthority authority = new SimpleGrantedAuthority(uri);
// 判断用户的权限集合是否包含请求的URL权限对象
boolean result = authorities.contains(authority);
return new AuthorizationDecision(result);
}
);
}
);
方法二、注解类设置访问控制(优选)
1. 需要在启动类中开启注解:@EnableMethodSecurity
package com.wunaiieq.tmp2024121105;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
@SpringBootApplication
@MapperScan("com.wunaiieq.tmp2024121105.mapper")
@EnableMethodSecurity
public class Tmp2024121105Application {
public static void main(String[] args) {
SpringApplication.run(Tmp2024121105Application.class, args);
}
}
2. controller对应的方法中增加注解
@GetMapping("/staff/find")
@PreAuthorize("hasAnyAuthority('/staff/find')")
public String findStaff() {
return "查询员工";
}
权限不足的处理方法
编写全写不足处理类,在权限不足时跳转指定页面,或弹窗等
权限不足的处理类
package com.wunaiieq.tmp2024121105.handler;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class MyAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
response.sendRedirect("/noPermission.html");
}
}
配置文件中增加处理权限不足的异常
httpSecurity.exceptionHandling().accessDeniedHandler(new MyAccessDeniedHandler());
原文地址:https://blog.csdn.net/wusuoweiieq/article/details/144429689
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!