当前位置: 首页 > news >正文

SpringBoot集成Spring security 2024.10(Spring Security 6.3.3)

SpringBoot集成Spring security 2024.10(Spring Security 6.3.3)

本文将简述如何快速集成spring security,实现简单登录和授权示例,具体情况根据实际业务细化。

jdk版本:jdk17
springboot版本:3.3.4
IntelliJ IDEA :2023.2.7
本文集成的相关框架:mybatis、lombok、swagger-ui、thymeleaf模板
Spring Security官网 : https://projects.spring.io/spring-security/
数据库(一般有用户表(用户id、用户名、密码、权限)、菜单表(菜单id、名称、路径)、角色表(角色id、角色名)、用户角色表(主键、用户id、角色id)、角色权限表(主键、角色id、菜单id、是否有权限)、用户菜单权限表(主键、用户id、资源id、是否有权限)此处比较简略只创建了用户表:

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;-- ----------------------------
-- Table structure for users
-- ----------------------------
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users`  (`id` int NOT NULL AUTO_INCREMENT,`user_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户名',`password` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '密码',`age` int NULL DEFAULT NULL COMMENT '年龄',`email` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '邮件',`auth` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '权限',PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;SET FOREIGN_KEY_CHECKS = 1;

什么是Spring security?

Spring Security是一个功能强大且高度可定制的身份验证和访问控制框架。它是保护基于Spring的应用程序的事实标准。Spring Security是一个专注于为Java应用程序提供身份验证和授权的框架。
在这里插入图片描述

验证和授权的作用?

验证:简言之就是用户登录控制,在用户使用系统时,一般打开系统就会让登录,登录一般有用户密码、手机验证码、人脸识别等登录方式,若输入信息校验正确则可进行更多操作。
授权:在一个系统中,可以把不同用户分成多种角色,与工作的人员组织架构一样,不同角色有不同权限。spring Security中有按照角色授权和资源授权两种方式。

前置环境一览:

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 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>3.3.4</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.example</groupId><artifactId>springBootMybatis</artifactId><version>0.0.1-SNAPSHOT</version><name>springBootMybatis</name><description>springBootMybatis</description><url/><licenses><license/></licenses><developers><developer/></developers><scm><connection/><developerConnection/><tag/><url/></scm><properties><java.version>17</java.version></properties><dependencies><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>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>3.0.3</version></dependency><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><scope>runtime</scope></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.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter-test</artifactId><version>3.0.3</version><scope>test</scope></dependency><dependency><groupId>org.springdoc</groupId><artifactId>springdoc-openapi-starter-webmvc-ui</artifactId><version>2.0.2</version></dependency><dependency><groupId>org.springdoc</groupId><artifactId>springdoc-openapi-starter-webmvc-api</artifactId><version>2.0.2</version></dependency><!--引入jsp--><!-- spring boot 内置tomcat jsp支持 --><dependency><groupId>org.apache.tomcat.embed</groupId><artifactId>tomcat-embed-jasper</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></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>

application.yml

server:port: 8081
spring:application:name: springBootMybatisdatasource:url: jdbc:mysql://localhost:3306/tea_data?severTimezone=UTCusername: tea_data_userpassword: tea_data_userdriver-class-name: com.mysql.cj.jdbc.Driverthymeleaf:prefix: classpath:/templates/suffix: .html
mybatis:mapper-locations: classpath:mapper/*.xmltype-aliases-package: com.example.springbootmybatis.pojo
springdoc:swagger-ui:path: /swagger-ui.html

项目结构:
在这里插入图片描述
下面开始集成Spring Security

1、创建用户管理相关业务,实现通过用户名查询用户信息方法

在这里插入图片描述
controller:此处getById方法页面无法访问,之前是RestController,为了返回页面使用了Controller. gotoUserManage方法用于主页面模拟菜单跳转。

//该代码用于登录成功后,跳转其他页面获取用户信息Authentication authentication = SecurityContextHolder.getContext().getAuthentication();if (authentication != null) {String currentUserName = authentication.getName();model.addAttribute("username", currentUserName);}

在这里插入图片描述

2.引入Spring security依赖

	 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-test</artifactId><scope>test</scope></dependency>

3.定义用户登录Controller

package com.example.springbootmybatis.login;import com.example.springbootmybatis.teaTypeFunction.pojo.TeaType;
import com.example.springbootmybatis.teaTypeFunction.service.TeaTypeService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;import java.security.Principal;
import java.util.Date;
import java.util.List;/*** @ClassName:Login* @Author: xuli* @Date: 2024/10/22 12:01* @Description: 用户登录控制器*/
@Controller
public class LoginController {Logger logger= LoggerFactory.getLogger(LoginController.class);@Autowiredprivate TeaTypeService teaTypeService;/*** 定义登录页面* @param request* @param model* @return*/@RequestMapping("/login")String login(HttpServletRequest request,Model model) {String errorMsg=request.getParameter("error");model.addAttribute("error",errorMsg);return "login";}/*** 跳转主页main* @param model* @param principal spring security提供的通道可获取用户信息* @return*/@RequestMapping("/main")public String gotoMainPage(Model model, Principal principal){String userName=principal.getName();model.addAttribute("userName",userName);logger.info(DateFormatUtils.format(new Date(),"YYYY-MM-dd HH:mm:ss")+userName+"登录成功");List<TeaType> teaTypes = teaTypeService.queryAllData();logger.info("获取到茶类信息如下:"+teaTypes);model.addAttribute("teaTypes",teaTypes);model.addAttribute("title","欢迎访问茶类页面");return "teaType";}/*** 退出登录,清空* @param request* @param response* @return*/@RequestMapping("/loginOut")String login(HttpServletRequest request, HttpServletResponse response) {//获取用户信息Authentication authentication = SecurityContextHolder.getContext().getAuthentication();if (authentication != null) {new SecurityContextLogoutHandler().logout(request, response, authentication);}return "redirect:/login?logout"; // 重定向到登录页面并带上logout参数}/*** 无权限自定义页面* @param request* @param response* @return*/@RequestMapping("/noPermission")String noPermission(HttpServletRequest request, HttpServletResponse response) {return "noPermission";}}

4、创建用户自定义登录页面、主页面、无权限页面

在这里插入图片描述

用户登录页:login.html,路径src/main/resources/templates/login.html
注意:form中的th:action="@{/login}"与上面controller定义的一致,否则点登录时会一致跳转登录页面

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org">
<head><title>Please Log In</title>
</head>
<body>
<h1>用户登录</h1><div th:if="${param.logout}">You have been logged out.</div>
<form th:action="@{/login}" method="post"><div ><label style="text-align: right">用户名:</label><input type="text" name="username" placeholder="用户名"/></div><div ><label style="text-align: right">密&emsp;码:</label><input type="password" name="password" placeholder="密码"/></div><div th:if="${param.error}" style="color: red">用户名或密码错误</div><input type="submit" value="登录" />
</form></body>
</html>

登录成功主页面:teaType.html,路径:src/main/resources/templates/teaType.html
th:href=“@{/loginOut}” 与controller定义的退出登录方法一致

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title th:text="${title}">Title</title>
</head>
<style>table {border-collapse: collapse;border: 1px solid black;width: 50%;}th, td {border: 1px solid #dddddd;padding: 8px;text-align: center;}</style>
<body>
<h1 th:text="'欢迎' + ${userName} + '登录!'"></h1>
<div style="text-align: right"><a style="text-align: right" th:href="@{/loginOut}" >退出登录</a>
</div>
<a href="http://localhost:8081/swagger-ui/index.html" TARGET="_blank">查看api</a><a th:href="@{/user/gotoUserManage}" TARGET="_blank">用户管理</a><h1>茶类清单</h1>
<table><tr><th>茶类名称</th><th>类型</th></tr><tr th:each="teaType:${teaTypes}"><td th:text="${teaType.teaName}"></td><td th:text="${teaType.type}"></td></tr>
</table></body>
</html>

无权限noPermission.html,路径:src/main/resources/templates/noPermission.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>权限不足</title>
</head>
<body>
<h1>您的权限不足,请联系管理员!</h1>
</body>
</html>

5、定义WebConfig,此类用于注册登录页面、主页面路径与视图关系,如不配置,直接访问将被拦截,访问登录和主页面都提示404。

package com.example.springbootmybatis.config;import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;/*** @ClassName:WebConfig* @Author: ciku* @Description: 注册视图*/
@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void addViewControllers(ViewControllerRegistry registry) {registry.addViewController("/login").setViewName("login");registry.addViewController("/teaType").setViewName("teaType");}
}

6、新增SecurityConfig spring security配置类

SecurityFilterChain 用户拦截请求、配置权限、用户登入登出、异常处理
UserDetailsService 获取用户信息,有两种方式内存模式、数据库对应。
PasswordEncoder 定义使用的加密方式,NoOpPasswordEncoder表示不加密,进行字符串直接比较。spring security提供了丰富的加密方式,可以按需定义。
在这里插入图片描述


package com.example.springbootmybatis.config;import com.example.springbootmybatis.user.pojo.UserVo;
import com.example.springbootmybatis.user.service.UserService;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
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.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.Authentication;
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.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;import java.io.IOException;/*** @ClassName:SecurityConfig* @Author: ciku* @Date: 2024/10/21 19:59* @Description: security配置类*/
@EnableWebSecurity
@Configuration
public class SecurityConfig {@Autowiredprivate UserService userService;/*** 定义过滤器拦截* @param http* @return* @throws Exception*/@Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception{http.authorizeHttpRequests(auth->auth.requestMatchers("/").permitAll()  // 公开访问.requestMatchers("/user/**").hasAnyAuthority("user_admin")//资源需具有的权限.requestMatchers("/teaType/**").hasAnyAuthority("guest","user_admin")//hasAnyAuthority 可传多个,其中一个匹配就可访问.anyRequest().authenticated())//每个请求都要认证.formLogin((form)-> form.loginPage("/login")//登录页面.successForwardUrl("/main")//登录成功跳转页面,如无效也可使用AuthenticationSuccessHandler.failureUrl("/login?error=true")//登录失败重定向登录页面,并提示错误信息.permitAll()).logout(logout->logout.logoutUrl("/loginOut"));//退出登录;http.exceptionHandling(handling->handling.accessDeniedHandler(new MyAccessDeniedHandler()));//权限不足返回页面return http.build();}private AuthenticationSuccessHandler authenticationSuccessHandler(){return  new AuthenticationSuccessHandler() {@Overridepublic void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {response.sendRedirect("/main");}};}/*** 获取用户信息* @param passwordEncoder* @return*/@Beanpublic UserDetailsService  userDetailsService(PasswordEncoder passwordEncoder){return new UserDetailsService() {@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {UserDetails user=null;if(!username.isBlank()){UserVo userVo= userService.getUserByName(username);if (userVo!=null){user= User.builder().username(userVo.getUserName()).password(passwordEncoder.encode(userVo.getPassword())).authorities(userVo.getAuth()).build();}}return user;}};}/* 内存模式直接设值@Beanpublic UserDetailsService  userDetailsService(PasswordEncoder passwordEncoder){UserDetails user= User.builder().username("xu").password("123456").authorities("USER").build();return new InMemoryUserDetailsManager(user);}*//*** 定义加密算法* @return*//*
*/@Beanpublic PasswordEncoder passwordEncoder(){return new BCryptPasswordEncoder(10);//使用BCrypt,加密强度,值越大安全性越高}}

@EnableWebSecurity 开启Security配置功能,若不加此配置,该类无法生效,将使用默认的方式
@Configuration 标识该类是配置类
requestMatchers 请求匹配,用户定义请求具有那些权限能访问或者公开
permitAll () 无条件允许访问
hasAnyAuthority 有任意一个匹配即可访问,传多个值
hasAuthority 有这个权限,只能配置一个权限
anyRequest().authenticated()) 所有请求都要认证后才能访问
loginPage 设置登录页面路径
loginProcessingUrl() 登录处理方法,常用于自定义处理方法
successForwardUrl 登录成功跳转页面
successHandler 登录成功处理类 .successHandler(authenticationSuccessHandler())
failureUrl 登录失败跳转页面,同理也可定义处理类

7、新增无权限处理配置类,实现AccessDeniedHandler,挑战无权限页面

package com.example.springbootmybatis.config;import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;import java.io.IOException;/*** @ClassName:MyAccessDeniedHandler* @Author: ciku* @Date: 2024/10/22 15:38* @Description: 定义权限不足返回页面*/
@Component
public class MyAccessDeniedHandler implements AccessDeniedHandler {@Overridepublic void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {response.sendRedirect("/noPermission");}
}

7、访问效果展示

(1)登录

在这里插入图片描述

(2)登录成功

数据库数据:
在这里插入图片描述
跳转主页面:
在这里插入图片描述

(3)登录失败提示用户名或密码错误

在这里插入图片描述

(4)退出登录,返回登录页面

在这里插入图片描述

(5)验证权限

在这里插入图片描述
根据配置访问user相关的需要具备user_admin权限,使用zhangs登录查看效果
在这里插入图片描述
zhangs登录成功点击用户管理,会提示权限不足
在这里插入图片描述
在这里插入图片描述

更换用户为xuli,提示跳转成功并获取了用户名,也可以放弃其他应用,此处配置.requestMatchers(“/teaType/**”).hasAnyAuthority(“guest”,“user_admin”)表示拥有guest权限和user_admin之一就可以访问
在这里插入图片描述
本例集成了swagger,当直接访问http://localhost:8081/swagger-ui/index.html会定位到登录页面
在这里插入图片描述

如有不当之处的可以发表评论指正


http://www.mrgr.cn/news/56188.html

相关文章:

  • 深度学习-机器学习与传统编程区别
  • 数组算法(代码随想录)
  • 【Flutter】基础组件:Container
  • 【参与感】小米口碑营销内部手册-读后感
  • 浅谈数据库选型
  • 前端开发 环境变量 process.env.NODE_ENV 是什么
  • 2024 四川省大学生信息安全技术大赛 安恒杯 部分 WP
  • 【网络原理】HTTP协议
  • 【智能制造-34】机器人算法工程师为什么一定要懂电机?
  • 图形平台API和WebAssembly AI
  • EEE与WOL的关系
  • 玩转springboot之springboot项目监测
  • 关于检索评价的一份介绍
  • java使用枚举类存常量字典值
  • 【Qt】控件——Qt输入类控件、常见的输入类控件、输入类控件的使用、Line Edit、Text Edit、Combo Box、Spin Box
  • 《地下蚁国》风灵月影十项修改器使用教程
  • LLM 量化新篇章:FlatQuant 的平坦之道
  • HTMX 和 WebStencils 白皮书
  • gazebo显示urdf
  • 三部门联合推铁路电子客票,百望云率先完成产品配置,助力财务服务数智化升级
  • 安达发|家电组装多厂协同APS计划排程软件介绍
  • 网关挂了服务还能正常运行吗?
  • Spring Boot 3.3 【八】整合实现高可用 Redis 集群
  • 【1024程序员节】如何快速掌握人工智能技术技能
  • 【人工智能】Transformers之Pipeline(二十):令牌分类(token-classification)
  • “销量飞跃秘籍:打造吸引力销售网络与革新招商策略“