1. security完成授权。
授权: 把当前用户具有的权限和对应的资源绑定的过程。授权一定发生在认证后。
定义一些资源接口
package com.zql.controller;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @program: spring-boot01
* @description:
* @author:
* @create: 2024-07-27 11:37
**/
@RestController
@RequestMapping("test")
public class test01 {
@GetMapping("info")
public Authentication info(){
//获取SecuityContext对象
SecurityContext context = SecurityContextHolder.getContext();
//把用户信息封装到Authentication对象中
Authentication authentication = context.getAuthentication();
UserDetails principal = (UserDetails) authentication.getPrincipal();
System.out.println(principal.getUsername());
return authentication;
}
@GetMapping("insert")
public String insert(){
System.out.println("添加用户");
return "添加用户";
}
@GetMapping("delete")
public String delete(){
System.out.println("删除用户");
return "删除用户";
}
@GetMapping("update")
public String update(){
System.out.println("修改用户");
return "修改用户";
}
@GetMapping("select")
public String select(){
System.out.println("查询用户");
return "查询用户";
}
}
修改配置类
package com.zql.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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;
/**
* @program: spring-boot01
* @description: Security configuration class
* @author:
* @create: 2024-07-27 10:58
**/
@Configuration
@EnableWebSecurity
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("zql")
.password(passwordEncoder().encode("123456"))
.roles("admin")
.authorities("test:select","test:insert","test:update")
.and()
.withUser("zql1")
.password(passwordEncoder().encode("123456"))
.roles("user")
.authorities("test:select","test:insert","test:update","test:delete");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin()
// 登录页面
.loginPage("/login.html")
// 登录处理地址
.loginProcessingUrl("/login")
// 登录成功后默认跳转地址
.successForwardUrl("/success")
.failureForwardUrl("/error")
.permitAll();
//资源和权限绑定
http.authorizeRequests().
antMatchers("/test/select").hasAnyAuthority("test:select")
.antMatchers("/test/insert").hasAnyAuthority("test:insert")
.antMatchers("/test/update").hasAnyAuthority("test:update")
.antMatchers("/test/delete").hasAnyAuthority("test:delete");
http.csrf().disable();
http.authorizeRequests().anyRequest().authenticated();
}
}
1.2 使用注解完成授权
上面的授权代码比较麻烦。 我们可以使用注解完成授权的过程。
开启security授权的注解驱动
在资源上使用注解
package com.zql.controller;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @program: spring-boot-secuity02
* @description:
* @author:
* @create: 2024-07-27 14:36
**/
@RestController()
@RequestMapping("/test")
public class TestController {
@GetMapping("info")
/**
* 获取当前认证信息。
*
* 本方法通过SecurityContextHolder获取当前的SecurityContext,进而得到Authentication对象。
* 这个对象包含了当前用户的认证信息,如用户名、权限等。方法返回这个Authentication对象,
* 可以用于进一步的权限检查或用户信息获取。
*
* @return 当前的Authentication对象,包含了用户的认证信息。
*/
public Authentication info() {
// 从SecurityContextHolder中获取当前的SecurityContext
//获取SecuityContext对象
SecurityContext context = SecurityContextHolder.getContext();
// 从SecurityContext中获取当前的Authentication对象
//把用户信息封装到Authentication对象中
Authentication authentication = context.getAuthentication();
// 将Authentication对象中的用户主体信息转换为UserDetails类型
UserDetails principal = (UserDetails) authentication.getPrincipal();
// 打印用户名,用于调试或日志记录
System.out.println(principal.getUsername());
// 返回Authentication对象,供外部使用
return authentication;
}
@PostMapping("/aaa")
public String error(){
return "redirect:/aaa.html";
}
@GetMapping("insert")
@PreAuthorize("hasAnyAuthority('test:insert')")
public String insert(){
System.out.println("添加用户");
return "添加用户";
}
@GetMapping("delete")
@PreAuthorize("hasAnyAuthority('test:delete')")
public String delete(){
System.out.println("删除用户");
return "删除用户";
}
@GetMapping("update")
@PreAuthorize("hasAnyAuthority('test:update')")
public String update(){
System.out.println("修改用户");
return "修改用户";
}
@GetMapping("select")
@PreAuthorize("hasAnyAuthority('test:select')")
public String select(){
System.out.println("查询用户");
return "查询用户";
}
@GetMapping("export")
@PreAuthorize("hasAnyAuthority('test:export')")
public String export(){
System.out.println("导出用户");
return "导出用户";
}
}
1.3 权限不足跳转指定页面
权限不足跳转的页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
权限不足, 请联系管理员!!!!!!!!
</body>
</html>
修改配置类
package com.zql.config;
import com.zql.service.MyUserDetailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
* @Author:
* @Description:
* @Date: Create in 10:43 2024/7/27
* 如果springboot的版本2.7.0以上
*/
@Configuration
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
//把输入的密码经过密码加密器加密后 数据库中的密码对比
@Bean
public PasswordEncoder passwordEncoder(){
PasswordEncoder passwordEncoder=new BCryptPasswordEncoder();
return passwordEncoder;
}
@Autowired
private MyUserDetailService userDetailService;
//配置文件中的账号和密码失效
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailService);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin()
//登录页面;
.loginPage("/login.html")
//登录的处理路径 默认 /login
.loginProcessingUrl("/login")
.successForwardUrl("/success") //登录成功转发的路径 必须为post请求
.failureForwardUrl("/fail") //登录失败转发的路径 必须为post请求
.permitAll(); //上面的请求路径无需认证
//指定权限不足跳转的页面
http.exceptionHandling().accessDeniedPage("/403.html");
http.csrf().disable();//禁用跨域伪造请求的过滤器
//除了上的请求,其他请求都需要认证
http.authorizeRequests().anyRequest().authenticated();
}
}
2.【源码分析】spring Security认证授权--了解
为什么需要分析认证得流程?
我们要通过数据库进行认证和授权。
2.1 结构总览
Spring security所解决的问题就是安全访问控制,而安全访问控制功能其实就是对所有进入系统的请求进行拦截,校验每个请求是否能够访问它所期望的资源。根据前边知识的学习,可以通过Filter或AoP等技术来实现,SpringSecurity对web资源的保护是靠==Filter=='实现的,所以从这个Filter来入手,逐步深入Spring Security 原理。当初始化Spring Security时,会创建一个名为SpringSecurityFilterChain的 Servlet过滤器,类型为org.springframework.security.web.FilterChainProxy,它实现了javax.servlet.Filter,因此外部的请求会经过此类,下图是 Spring Security过虑器链结构图:
上图说明:
FilterchainProxy是一个代理,真正起作用的是FilterChainProxy 中securityFilterChain所包含的各个Filter,同时这些Filter作为Bean被Spring管理,它们是Spring Security核心,各有各的职责,但他们并不直接处理用户的认证,也不直接处理用户的授权,而是把它们交给了认证管理器(AuthenticationManager)和决策管理器(AccessDecisionManager)进行处理下图是 FilterChainProxy相关类的UML图示
2.2 过滤器链中主要的几个过滤器及其作用
2.2.1 SecurityContextPersistenceFi1ter
这个Filter是整个拦截过程的入口和出口(也就是第一个和最后一个拦截器),会在请求开始时从配置好的 SecurityContextRepesitory 中获取SecurityContext,然后把它设置给securityContextHolder.在请求完成后将SecurityContextHolder持有的SecurityContext再保存到配置好的SecurityContextRepository ,同时清除securityContextHolder所持有的SecurityContext;
2.2.2 UsernamePasswordAuthenticationFilter
用于处理来自表单提交的认证。该表单必须提供对应的用户名和密码,其内部还有登录成功或失败后进行处理的AuthenticationSuccessHandler和AuthenticationFailureHandler,这些都可以根据需求做相关改变;
2.2.3 FilterSecurityInterceptor
是用于保护web资源的,使用AccessDecisionManager对当前用户进行授权访问;
2.2.4 ExceptionTranslationFilter
能够捕获来自Filterchain所有的异常,并进行处理。但是它只会处理两类异常:AuthenticationException和 AccessDeniedException,其它的异常它会继续抛出。
2.3【源码分析】Spring security 认证工作流程
UsernamePasswordAuthenticationFilter (attemptAuthentication)
ProviderManager (authenticate) DaoAuthenticationProvider (retrieveUser) AbstractUserDetailsAuthenticationProvider (authenticate)
2.3.1 认证流程图
查询数据库进行比对。
查询用户信息的代码--->UserDetailsService中loadUserByUsername该方法。 我们只需要重写该方法即可。
3. 自定义UserDetailsService接口类
自定义service
package com.zql.service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zql.eneity.Permission;
import com.zql.eneity.User;
import com.zql.mapper.PermissionMapper;
import com.zql.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
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 java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* @program: spring-boot-secuity02
* @description:
* @author:
* @create: 2024-07-29 14:57
**/
@Service
public class MyUserDetailService implements UserDetailsService {
@Autowired
private UserMapper userMapper;
@Autowired
private PermissionMapper permissionMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//根据账号查询用户信息--username必须唯一
QueryWrapper<User> wrapper=new QueryWrapper<>();
wrapper.eq("username",username);
User user = userMapper.selectOne(wrapper);
//判断用户是否存在
if(Objects.nonNull(user)){
//查询当前用户具有的权限
Collection<Permission> permissions = permissionMapper.selectByUserId(user.getUserid());
//List<A>--JDK8特性->List<B>
// List<SimpleGrantedAuthority> list=new ArrayList<>() ;
// for(Permission p:permissions){
// SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(p.getPercode());
// list.add(simpleGrantedAuthority);
// }
List<SimpleGrantedAuthority> collect = permissions.stream().map(item -> new SimpleGrantedAuthority(item.getPercode())).collect(Collectors.toList());
return new org.springframework.security.core.userdetails.User(username,user.getUserpwd(),collect);
}
return null;
}
}
修改配置类
package com.zql.config;
import com.zql.service.MyUserDetailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
* @Author:
* @Description:
* @Date: Create in 10:43 2024/7/27
* 如果springboot的版本2.7.0以上
*/
@Configuration
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
//把输入的密码经过密码加密器加密后 数据库中的密码对比
@Bean
public PasswordEncoder passwordEncoder(){
PasswordEncoder passwordEncoder=new BCryptPasswordEncoder();
return passwordEncoder;
}
@Autowired
private MyUserDetailService userDetailService;
//配置文件中的账号和密码失效
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailService);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin()
//登录页面;
.loginPage("/login.html")
//登录的处理路径 默认 /login
.loginProcessingUrl("/login")
.successForwardUrl("/success") //登录成功转发的路径 必须为post请求
.failureForwardUrl("/fail") //登录失败转发的路径 必须为post请求
.permitAll(); //上面的请求路径无需认证
//指定权限不足跳转的页面
http.exceptionHandling().accessDeniedPage("/403.html");
http.csrf().disable();//禁用跨域伪造请求的过滤器
//除了上的请求,其他请求都需要认证
http.authorizeRequests().anyRequest().authenticated();
}
}
4. springsecurity整合thymeleaf
模板引擎等价于jsp.
数据库
/*
Navicat Premium Data Transfer
Source Server : gz02
Source Server Type : MySQL
Source Server Version : 80032
Source Host : localhost:3306
Source Schema : security
Target Server Type : MySQL
Target Server Version : 80032
File Encoding : 65001
Date: 24/11/2023 11:16:37
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for sys_permission
-- ----------------------------
DROP TABLE IF EXISTS `sys_permission`;
CREATE TABLE `sys_permission` (
`perid` int(0) NOT NULL AUTO_INCREMENT,
`pername` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
`percode` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`perid`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of sys_permission
-- ----------------------------
INSERT INTO `sys_permission` VALUES (1, '用户查询', 'user:query');
INSERT INTO `sys_permission` VALUES (2, '用户添加', 'user:add');
INSERT INTO `sys_permission` VALUES (3, '用户修改', 'user:update');
INSERT INTO `sys_permission` VALUES (4, '用户删除', 'user:delete');
INSERT INTO `sys_permission` VALUES (5, '用户导出', 'user:export');
-- ----------------------------
-- Table structure for sys_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role` (
`roleid` int(0) NOT NULL AUTO_INCREMENT,
`rolename` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`roleid`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of sys_role
-- ----------------------------
INSERT INTO `sys_role` VALUES (1, '管理员');
INSERT INTO `sys_role` VALUES (2, '测试人员');
INSERT INTO `sys_role` VALUES (3, '普通用户');
-- ----------------------------
-- Table structure for sys_role_permission
-- ----------------------------
DROP TABLE IF EXISTS `sys_role_permission`;
CREATE TABLE `sys_role_permission` (
`perid` int(0) NULL DEFAULT NULL,
`roleid` int(0) NULL DEFAULT NULL
) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of sys_role_permission
-- ----------------------------
INSERT INTO `sys_role_permission` VALUES (2, 1);
INSERT INTO `sys_role_permission` VALUES (1, 1);
INSERT INTO `sys_role_permission` VALUES (3, 1);
INSERT INTO `sys_role_permission` VALUES (4, 1);
INSERT INTO `sys_role_permission` VALUES (2, 2);
INSERT INTO `sys_role_permission` VALUES (1, 2);
INSERT INTO `sys_role_permission` VALUES (3, 2);
INSERT INTO `sys_role_permission` VALUES (1, 3);
INSERT INTO `sys_role_permission` VALUES (5, 3);
-- ----------------------------
-- Table structure for sys_user
-- ----------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
`userid` int(0) NOT NULL AUTO_INCREMENT,
`username` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
`userpwd` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
`sex` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
`address` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`userid`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of sys_user
-- ----------------------------
INSERT INTO `sys_user` VALUES (1, '张三', '$2a$10$cI7e7bgSs9.9nNHhxKO9LuK/Ll.AeZwgUyZb77oD2y3UwwZyZhWG6', '男', '郑州');
INSERT INTO `sys_user` VALUES (2, '李四', '$2a$10$cI7e7bgSs9.9nNHhxKO9LuK/Ll.AeZwgUyZb77oD2y3UwwZyZhWG6', '男', '北京');
INSERT INTO `sys_user` VALUES (3, '王五', '$2a$10$cI7e7bgSs9.9nNHhxKO9LuK/Ll.AeZwgUyZb77oD2y3UwwZyZhWG6', '女', '杭州');
-- ----------------------------
-- Table structure for sys_user_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_user_role`;
CREATE TABLE `sys_user_role` (
`userid` int(0) NOT NULL,
`roleid` int(0) NULL DEFAULT NULL
) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of sys_user_role
-- ----------------------------
INSERT INTO `sys_user_role` VALUES (1, 1);
INSERT INTO `sys_user_role` VALUES (2, 2);
INSERT INTO `sys_user_role` VALUES (3, 3);
INSERT INTO `sys_user_role` VALUES (1, 2);
SET FOREIGN_KEY_CHECKS = 1;
创建工程
依赖
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.12.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.ykq</groupId>
<artifactId>qy174-spring-boot-security03</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>qy174-spring-boot-security03</name>
<description>qy174-spring-boot-security03</description>
<properties>
<java.version>8</java.version>
</properties>
<dependencies>
<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>
<!--thymeleaf和springsecurity整合的依赖-->
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
配置文件
server.port=8080
spring.datasource.url=jdbc:mysql://localhost:3306/thymeleaf?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
mybatis-plus.mapper-locations=classpath*:mapper/*Mapper.xml
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
实体类使用MybatisX-Generator生成就行
dao
public interface PermissionMapper extends BaseMapper<Permission> {
public List<Permission> selectByUserId(Integer userId);
}
service类
package com.zql.service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zql.eneity.Permission;
import com.zql.eneity.User;
import com.zql.mapper.PermissionMapper;
import com.zql.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
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 java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* @program: spring-boot-secuity02
* @description:
* @author:
* @create: 2024-07-29 14:57
**/
@Service
public class MyUserDetailService implements UserDetailsService {
@Autowired
private UserMapper userMapper;
@Autowired
private PermissionMapper permissionMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//根据账号查询用户信息--username必须唯一
QueryWrapper<User> wrapper=new QueryWrapper<>();
wrapper.eq("username",username);
User user = userMapper.selectOne(wrapper);
//判断用户是否存在
if(Objects.nonNull(user)){
//查询当前用户具有的权限
Collection<Permission> permissions = permissionMapper.selectByUserId(user.getUserid());
//List<A>--JDK8特性->List<B>
// List<SimpleGrantedAuthority> list=new ArrayList<>() ;
// for(Permission p:permissions){
// SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(p.getPercode());
// list.add(simpleGrantedAuthority);
// }
List<SimpleGrantedAuthority> collect = permissions.stream().map(item -> new SimpleGrantedAuthority(item.getPercode())).collect(Collectors.toList());
return new org.springframework.security.core.userdetails.User(username,user.getUserpwd(),collect);
}
return null;
}
}
配置类使用上方那个就行
在templates里加个登录成功后的页面
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a href="/user/query" sec:authorize="hasAuthority('user:query')">查询用户</a><br>
<a href="/user/add" sec:authorize="hasAuthority('user:add')">添加用户</a><br>
<a href="/user/update" sec:authorize="hasAuthority('user:update')">修改用户</a><br>
<a href="/user/delete" sec:authorize="hasAuthority('user:delete')">删除用户</a><br>
<a href="/user/export" sec:authorize="hasAuthority('user:export')">导出用户</a><br>
</body>
</html>
package com.zql.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
/**
* @program: spring-boot01
* @description:
* @author: 赵庆龙
* @create: 2024-07-27 10:01
**/
@Controller()
public class HelloController {
@GetMapping("hello")
public String hello() {
return "hello";
}
@PostMapping("success")
public String success(){
return "index";//redirect:index.html
}
}
这里跳转到成功页面时不要使用重定向 使用上面的方法视图