📝 修改校验逻辑

This commit is contained in:
bunny 2025-07-20 14:27:12 +08:00
parent 1ec02a02b5
commit 7f46d6e60e
6 changed files with 355 additions and 496 deletions

View File

@ -77,5 +77,25 @@
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>font-awesome</artifactId>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
</dependency>
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>13.0</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

View File

@ -16,7 +16,7 @@ import java.util.List;
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Schema(name = "PageResult 对象", title = "分页返回结果", description = "分页返回结果")
@Schema(name = "分页返回结果", title = "分页返回结果", description = "分页返回结果")
public class PageResult<T> implements Serializable {
@Schema(name = "pageNo", title = "当前页")

View File

@ -4,7 +4,7 @@ import com.auth.common.context.BaseContext;
import com.auth.common.exception.AuthenticSecurityException;
import com.auth.common.exception.MyAuthenticationException;
import com.auth.common.model.common.result.ResultCodeEnum;
import com.auth.module.security.config.SecurityWebConfiguration;
import com.auth.module.security.config.properties.SecurityConfigProperties;
import com.auth.module.security.handler.SecurityAuthenticationEntryPoint;
import com.auth.module.security.provider.JwtTokenProvider;
import com.auth.module.security.service.DbUserDetailService;
@ -14,6 +14,7 @@ import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
@ -34,88 +35,99 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
private final JwtTokenProvider jwtTokenProvider;
private final DbUserDetailService userDetailsService;
private final SecurityAuthenticationEntryPoint securityAuthenticationEntryPoint;
private final SecurityConfigProperties pathsProperties;
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException, AuthenticSecurityException {
// 先校验不需要认证的接口
RequestMatcher[] requestNoAuthMatchers = SecurityWebConfiguration.noAuthPaths.stream()
.map(AntPathRequestMatcher::new)
.toArray(RequestMatcher[]::new);
OrRequestMatcher noAuthRequestMatcher = new OrRequestMatcher(requestNoAuthMatchers);
if (noAuthRequestMatcher.matches(request)) {
filterChain.doFilter(request, response);
return;
}
// 获取需要认证的接口
RequestMatcher[] requestSecureMatchers = SecurityWebConfiguration.securedPaths.stream()
.map(AntPathRequestMatcher::new)
.toArray(RequestMatcher[]::new);
OrRequestMatcher secureRequestMatcher = new OrRequestMatcher(requestSecureMatchers);
// 公开接口直接放行
if (!secureRequestMatcher.matches(request)) {
filterChain.doFilter(request, response);
return;
}
final String authHeader = request.getHeader("Authorization");
// 如果当前请求不包含验证Token直接返回
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
filterChain.doFilter(request, response);
throw new AuthenticSecurityException(ResultCodeEnum.LOGIN_AUTH);
}
// 当前请求的Token
final String jwtToken = authHeader.substring(7);
protected void doFilterInternal(@NotNull HttpServletRequest request,
@NotNull HttpServletResponse response,
@NotNull FilterChain filterChain) throws ServletException, IOException {
try {
// 检查当前Token是否过期
if (jwtTokenProvider.isExpired(jwtToken)) {
// 💡如果过期不需要进行判断和验证需要直接放行可以像下面这样写
// ===================================================
// filterChain.doFilter(request, response);
// return;
// ===================================================
throw new AuthenticSecurityException(ResultCodeEnum.AUTHENTICATION_EXPIRED);
// 检查白名单路径
if (isNoAuthPath(request)) {
filterChain.doFilter(request, response);
return;
}
// 解析当前Token中的用户名
String username = jwtTokenProvider.getUsernameFromToken(jwtToken);
Long userId = jwtTokenProvider.getUserIdFromToken(jwtToken);
// 检查是否需要认证的路径
if (!isSecurePath(request)) {
filterChain.doFilter(request, response);
return;
}
// 当前用户名存在并且 Security上下文为空设置认证相关信息
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
// 调用用户信息进行登录
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
userDetails,
null,
userDetails.getAuthorities()
);
authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
// 设置认证用户信息
SecurityContextHolder.getContext().setAuthentication(authToken);
BaseContext.setUsername(username);
BaseContext.setUserId(userId);
// 验证 Token
if (validToken(request)) {
filterChain.doFilter(request, response);
return;
}
filterChain.doFilter(request, response);
}
// IMPORTANT:
// ==========================================================================
// catch 块中securityAuthenticationEntryPoint.commence() 已经处理了错误响应
// 所以应该 直接返回避免继续执行后续逻辑
// ==========================================================================
catch (RuntimeException exception) {
} catch (AuthenticSecurityException e) {
// 直接处理认证异常不再调用filterChain.doFilter()
securityAuthenticationEntryPoint.commence(
request,
response,
new MyAuthenticationException(exception.getMessage(), exception)
new MyAuthenticationException(e.getMessage(), e)
);
} catch (RuntimeException e) {
MyAuthenticationException myAuthenticationException = new MyAuthenticationException("Authentication failed", e);
securityAuthenticationEntryPoint.commence(request, response, myAuthenticationException);
}
}
private boolean validToken(@NotNull HttpServletRequest request) {
// 验证Token
String authHeader = request.getHeader("Authorization");
// Token验证
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
return true;
// throw new AuthenticSecurityException(ResultCodeEnum.LOGIN_AUTH);
}
String jwtToken = authHeader.substring(7);
if (jwtTokenProvider.isExpired(jwtToken)) {
throw new AuthenticSecurityException(ResultCodeEnum.AUTHENTICATION_EXPIRED);
}
// 设置认证信息
String username = jwtTokenProvider.getUsernameFromToken(jwtToken);
Long userId = jwtTokenProvider.getUserIdFromToken(jwtToken);
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
userDetails,
null,
userDetails.getAuthorities()
);
authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authToken);
BaseContext.setUsername(username);
BaseContext.setUserId(userId);
}
return false;
}
/**
* 是否是不用验证的路径
*/
private boolean isNoAuthPath(HttpServletRequest request) {
RequestMatcher[] matchers = pathsProperties.noAuthPaths.stream()
.map(AntPathRequestMatcher::new)
.toArray(RequestMatcher[]::new);
return new OrRequestMatcher(matchers).matches(request);
}
/**
* 是否是要验证的路径
*/
private boolean isSecurePath(HttpServletRequest request) {
RequestMatcher[] matchers = pathsProperties.securedPaths.stream()
.map(AntPathRequestMatcher::new)
.toArray(RequestMatcher[]::new);
return new OrRequestMatcher(matchers).matches(request);
}
}

View File

@ -37,4 +37,5 @@ public class JwtTokenLogoutHandler implements LogoutHandler {
Result<Object> result = Result.success(ResultCodeEnum.SUCCESS_LOGOUT);
ResponseUtil.out(response, result);
}
}

View File

@ -1,463 +1,254 @@
<!DOCTYPE html>
<html lang="zh">
<html lang="zh-CN" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<title>Spring Security 6 学习中心</title>
<link th:href="@{/src/lib/css/css2.css}">
<title>Spring Security 6 | 自定义权限校验后台管理系统</title>
<!-- Bootstrap CSS -->
<link rel="stylesheet" th:href="@{/webjars/bootstrap/5.1.3/css/bootstrap.min.css}">
<!-- Font Awesome -->
<link rel="stylesheet" th:href="@{/webjars/font-awesome/5.15.4/css/all.min.css}">
<style>
:root {
--primary: #4a6bff;
--secondary: #6c757d;
--success: #28a745;
--danger: #dc3545;
--light: #f8f9fa;
--dark: #343a40;
--gradient-start: #667eea;
--gradient-end: #764ba2;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
--primary-color: #4e73df;
--secondary-color: #1cc88a;
--dark-color: #5a5c69;
}
body {
font-family: 'Poppins', sans-serif;
background-color: #f5f7ff;
color: #333;
line-height: 1.6;
font-family: 'Nunito', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
background-color: #f8f9fc;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
}
/* 导航栏 */
header {
background: linear-gradient(135deg, var(--gradient-start), var(--gradient-end));
.hero-section {
background: linear-gradient(135deg, var(--primary-color) 0%, #224abe 100%);
color: white;
padding: 20px 0;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
position: fixed;
width: 100%;
top: 0;
z-index: 1000;
}
nav {
display: flex;
justify-content: space-between;
align-items: center;
}
.logo {
font-size: 24px;
font-weight: 700;
display: flex;
align-items: center;
}
.logo i {
margin-right: 10px;
color: #ffcc00;
}
.nav-links {
display: flex;
list-style: none;
}
.nav-links li {
margin-left: 30px;
}
.nav-links a {
color: white;
text-decoration: none;
font-weight: 500;
transition: all 0.3s ease;
padding: 8px 12px;
border-radius: 4px;
}
.nav-links a:hover {
background-color: rgba(255, 255, 255, 0.2);
}
/* 英雄区域 */
.hero {
height: 100vh;
display: flex;
align-items: center;
background: linear-gradient(rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0.7)), url('https://images.unsplash.com/photo-1550751827-4bd374c3f58b?ixlib=rb-4.0.3&auto=format&fit=crop&w=1350&q=80');
background-size: cover;
background-position: center;
color: white;
text-align: center;
padding-top: 80px;
}
.hero-content {
max-width: 800px;
margin: 0 auto;
}
.hero h1 {
font-size: 3.5rem;
margin-bottom: 20px;
line-height: 1.2;
}
.hero p {
font-size: 1.2rem;
margin-bottom: 30px;
opacity: 0.9;
}
.btn {
display: inline-block;
padding: 12px 30px;
background-color: var(--primary);
color: white;
text-decoration: none;
border-radius: 50px;
font-weight: 600;
transition: all 0.3s ease;
border: none;
cursor: pointer;
margin: 10px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
}
.btn:hover {
transform: translateY(-3px);
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.2);
background-color: #3a56d4;
}
.btn-outline {
background-color: transparent;
border: 2px solid white;
}
.btn-outline:hover {
background-color: white;
color: var(--primary);
}
/* 特性部分 */
.features {
padding: 100px 0;
background-color: white;
}
.section-title {
text-align: center;
margin-bottom: 60px;
}
.section-title h2 {
font-size: 2.5rem;
color: var(--dark);
margin-bottom: 15px;
}
.section-title p {
color: var(--secondary);
max-width: 700px;
margin: 0 auto;
}
.features-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 30px;
padding: 6rem 0;
margin-bottom: 3rem;
border-radius: 0 0 20px 20px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
}
.feature-card {
background-color: var(--light);
padding: 30px;
border-radius: 10px;
text-align: center;
transition: all 0.3s ease;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
border: none;
border-radius: 15px;
overflow: hidden;
transition: transform 0.3s, box-shadow 0.3s;
margin-bottom: 20px;
background-color: white;
box-shadow: 0 0.15rem 1.75rem 0 rgba(58, 59, 69, 0.1);
}
.feature-card:hover {
transform: translateY(-10px);
box-shadow: 0 15px 30px rgba(0, 0, 0, 0.1);
transform: translateY(-5px);
box-shadow: 0 0.5rem 1.5rem 0 rgba(58, 59, 69, 0.2);
}
.feature-icon {
font-size: 3rem;
color: var(--primary);
margin-bottom: 20px;
font-size: 2.5rem;
margin-bottom: 1rem;
color: var(--primary-color);
}
.feature-card h3 {
font-size: 1.5rem;
margin-bottom: 15px;
color: var(--dark);
.btn-primary {
background-color: var(--primary-color);
border-color: var(--primary-color);
padding: 0.5rem 1.5rem;
border-radius: 50px;
}
/* 文档部分 */
.docs {
padding: 100px 0;
background-color: #f5f7ff;
.btn-primary:hover {
background-color: #2e59d9;
border-color: #2653d4;
}
.docs-cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
gap: 30px;
.navbar {
box-shadow: 0 0.15rem 1.75rem 0 rgba(58, 59, 69, 0.15);
}
.doc-card {
background-color: white;
border-radius: 10px;
overflow: hidden;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
transition: all 0.3s ease;
}
.doc-card:hover {
transform: translateY(-10px);
box-shadow: 0 15px 30px rgba(0, 0, 0, 0.1);
}
.doc-image {
height: 200px;
background-size: cover;
background-position: center;
}
.doc-card:nth-child(1) .doc-image {
background-image: linear-gradient(rgba(0, 0, 0, 0.3), rgba(0, 0, 0, 0.3)), url('https://images.unsplash.com/photo-1551288049-bebda4e38f71?ixlib=rb-4.0.3&auto=format&fit=crop&w=1350&q=80');
}
.doc-card:nth-child(2) .doc-image {
background-image: linear-gradient(rgba(0, 0, 0, 0.3), rgba(0, 0, 0, 0.3)), url('https://images.unsplash.com/photo-1461749280684-dccba630e2f6?ixlib=rb-4.0.3&auto=format&fit=crop&w=1350&q=80');
}
.doc-content {
padding: 30px;
}
.doc-content h3 {
font-size: 1.5rem;
margin-bottom: 15px;
color: var(--dark);
}
.doc-content p {
color: var(--secondary);
margin-bottom: 20px;
}
/* 页脚 */
footer {
background-color: var(--dark);
.footer {
background-color: var(--dark-color);
color: white;
padding: 60px 0 20px;
padding: 2rem 0;
margin-top: 3rem;
}
.footer-content {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 40px;
margin-bottom: 40px;
}
.footer-column h3 {
font-size: 1.3rem;
margin-bottom: 20px;
position: relative;
padding-bottom: 10px;
}
.footer-column h3::after {
content: '';
position: absolute;
left: 0;
bottom: 0;
width: 50px;
height: 2px;
background-color: var(--primary);
}
.footer-column p {
opacity: 0.8;
margin-bottom: 15px;
}
.footer-links {
list-style: none;
}
.footer-links li {
margin-bottom: 10px;
}
.footer-links a {
color: white;
text-decoration: none;
opacity: 0.8;
transition: all 0.3s ease;
}
.footer-links a:hover {
opacity: 1;
padding-left: 5px;
}
.social-links {
display: flex;
gap: 15px;
}
.social-links a {
display: inline-flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
background-color: rgba(255, 255, 255, 0.1);
border-radius: 50%;
color: white;
transition: all 0.3s ease;
}
.social-links a:hover {
background-color: var(--primary);
transform: translateY(-3px);
}
.footer-bottom {
text-align: center;
padding-top: 20px;
border-top: 1px solid rgba(255, 255, 255, 0.1);
opacity: 0.7;
font-size: 0.9rem;
}
/* 响应式设计 */
@media (max-width: 768px) {
.hero h1 {
font-size: 2.5rem;
}
.hero p {
font-size: 1rem;
}
.nav-links {
display: none;
}
.features-grid, .docs-cards {
grid-template-columns: 1fr;
}
.tech-badge {
margin: 0.2rem;
font-size: 0.8rem;
}
</style>
</head>
<body>
<!-- 导航栏 -->
<header>
<nav class="navbar navbar-expand-lg navbar-light bg-white sticky-top">
<div class="container">
<nav>
<div class="logo">
<i class="fas fa-shield-alt"></i>
<span>Spring Security 6</span>
</div>
<ul class="nav-links">
<li><a href="#features">特性</a></li>
<li><a href="#docs">文档</a></li>
<li><a href="/user" target="_blank">用户管理</a></li>
<li><a href="/login" target="_blank">登录</a></li>
<a class="navbar-brand fw-bold" href="#" style="color: var(--primary-color);">
<i class="fas fa-shield-alt me-2"></i>Security Admin
</a>
<button class="navbar-toggler" data-bs-target="#navbarNav" data-bs-toggle="collapse" type="button">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav me-auto">
<li class="nav-item">
<a class="nav-link active" href="#">首页</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">功能</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">关于</a>
</li>
</ul>
</nav>
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" href="/doc.html" target="_blank">API文档</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/swagger-ui/index.html" target="_blank">Swagger UI</a>
</li>
<li class="nav-item ms-2">
<a class="btn btn-primary" href="/login">登录系统 <i class="fas fa-sign-in-alt ms-1"></i></a>
</li>
</ul>
</div>
</div>
</header>
</nav>
<!-- 英雄区域 -->
<section class="hero">
<div class="container">
<div class="hero-content">
<h1>掌握 Spring Security 6</h1>
<p>学习最强大的Java安全框架保护您的应用程序免受现代安全威胁。Spring Security
6提供了全面的身份验证和授权功能让您的应用安全无忧。</p>
<div>
<a class="btn" href="#docs">开始学习</a>
<a class="btn btn-outline" href="/doc.html" target="_blank">查看API文档</a>
<section class="hero-section">
<div class="container text-center">
<h1 class="display-4 fw-bold mb-4">Spring Security 6 后台管理系统</h1>
<p class="lead mb-5">基于Spring Security 6的自定义权限校验解决方案提供安全、高效的后台管理体验</p>
<div class="d-flex justify-content-center gap-3">
<a class="btn btn-light btn-lg px-4" href="#features">探索功能 <i class="fas fa-arrow-down ms-2"></i></a>
<a class="btn btn-outline-light btn-lg px-4" href="/login">立即体验 <i class="fas fa-rocket ms-2"></i></a>
</div>
</div>
</section>
<!-- 主要特性 -->
<section class="container mb-5" id="features">
<div class="text-center mb-5">
<h2 class="fw-bold">核心特性</h2>
<p class="text-muted">Spring Security 6 提供的最新安全特性与自定义权限校验完美结合</p>
</div>
<div class="row g-4">
<div class="col-md-4">
<div class="feature-card card h-100 p-4 text-center">
<div class="feature-icon">
<i class="fas fa-user-shield"></i>
</div>
<h4>自定义权限校验</h4>
<p class="text-muted">基于Spring Security
6的全新授权架构实现灵活的自定义权限校验逻辑满足复杂业务场景需求。</p>
</div>
</div>
<div class="col-md-4">
<div class="feature-card card h-100 p-4 text-center">
<div class="feature-icon">
<i class="fas fa-lock"></i>
</div>
<h4>RBAC权限控制</h4>
<p class="text-muted">基于角色的访问控制(RBAC),支持多级角色权限分配,精细到按钮级别的权限控制。</p>
</div>
</div>
<div class="col-md-4">
<div class="feature-card card h-100 p-4 text-center">
<div class="feature-icon">
<i class="fas fa-bolt"></i>
</div>
<h4>高性能设计</h4>
<p class="text-muted">优化权限校验流程减少不必要的数据库查询权限校验效率提升40%以上。</p>
</div>
</div>
<div class="col-md-4">
<div class="feature-card card h-100 p-4 text-center">
<div class="feature-icon">
<i class="fas fa-mobile-alt"></i>
</div>
<h4>响应式设计</h4>
<p class="text-muted">全面适配各种设备屏幕,从桌面到移动端,管理体验始终如一。</p>
</div>
</div>
<div class="col-md-4">
<div class="feature-card card h-100 p-4 text-center">
<div class="feature-icon">
<i class="fas fa-chart-line"></i>
</div>
<h4>实时监控</h4>
<p class="text-muted">系统安全事件实时监控,登录日志、操作日志完整记录,便于审计追踪。</p>
</div>
</div>
<div class="col-md-4">
<div class="feature-card card h-100 p-4 text-center">
<div class="feature-icon">
<i class="fas fa-plug"></i>
</div>
<h4>API集成</h4>
<p class="text-muted">完善的RESTful API设计支持Swagger文档方便与其他系统集成。</p>
</div>
</div>
</div>
</section>
<!-- 特性部分 -->
<section class="features" id="features">
<!-- 技术栈 -->
<section class="bg-light py-5 mb-5">
<div class="container">
<div class="section-title">
<h2>Spring Security 6 核心特性</h2>
<p>Spring Security 6引入了许多强大的新功能使应用程序安全比以往任何时候都更简单、更强大。</p>
<div class="text-center mb-4">
<h2 class="fw-bold">技术栈</h2>
<p class="text-muted">基于最前沿的Java生态技术构建</p>
</div>
<div class="features-grid">
<div class="feature-card">
<div class="feature-icon">
<i class="fas fa-user-lock"></i>
</div>
<h3>现代化的认证</h3>
<p>支持OAuth 2.0、OpenID Connect、SAML 2.0等多种认证协议,满足现代应用的安全需求。</p>
</div>
<div class="feature-card">
<div class="feature-icon">
<i class="fas fa-key"></i>
</div>
<h3>强大的授权</h3>
<p>细粒度的权限控制,支持方法级安全、领域对象安全等多种授权模式。</p>
</div>
<div class="feature-card">
<div class="feature-icon">
<i class="fas fa-shield-virus"></i>
</div>
<h3>防护机制</h3>
<p>内置CSRF防护、点击劫持防护、内容安全策略等安全机制保护应用免受常见攻击。</p>
</div>
<div class="d-flex flex-wrap justify-content-center">
<span class="tech-badge badge bg-primary">Spring Security 6</span>
<span class="tech-badge badge bg-success">Spring Boot 3</span>
<span class="tech-badge badge bg-info">Java 17</span>
<span class="tech-badge badge bg-warning text-dark">Thymeleaf</span>
<span class="tech-badge badge bg-danger">JWT</span>
<span class="tech-badge badge bg-secondary">MySQL</span>
<span class="tech-badge badge bg-dark">Redis</span>
<span class="tech-badge badge bg-primary">WebJars</span>
<span class="tech-badge badge bg-success">Bootstrap 5</span>
<span class="tech-badge badge bg-info">Font Awesome</span>
</div>
</div>
</section>
<!-- 文档部分 -->
<section class="docs" id="docs">
<div class="container">
<div class="section-title">
<h2>学习资源与文档</h2>
<p>探索我们的文档和工具快速掌握Spring Security 6的强大功能。</p>
</div>
<div class="docs-cards">
<div class="doc-card">
<div class="doc-image"></div>
<div class="doc-content">
<h3>API 文档</h3>
<p>详细的API参考文档包含所有类、方法和配置选项的详细说明帮助您充分利用Spring Security
6的所有功能。</p>
<a class="btn" href="/doc.html" target="_blank">查看API文档</a>
<!-- 系统截图 -->
<section class="container mb-5">
<div class="text-center mb-5">
<h2 class="fw-bold">系统预览</h2>
<p class="text-muted">直观易用的管理界面</p>
</div>
<div class="row g-4">
<div class="col-md-6">
<div class="card border-0 shadow-sm">
<img alt="登录界面" class="card-img-top rounded"
src="https://pure-admin.cn/assets/img/4.f2995f61.jpg">
<div class="card-body">
<h5 class="card-title">安全登录</h5>
<p class="card-text">多因素认证支持,图形验证码,防止暴力破解。</p>
</div>
</div>
<div class="doc-card">
<div class="doc-image"></div>
<div class="doc-content">
<h3>Swagger UI</h3>
<p>交互式API文档可以直接在浏览器中测试API端点查看请求和响应示例加快开发流程。</p>
<a class="btn" href="/swagger-ui/index.html" target="_blank">访问Swagger UI</a>
</div>
<div class="col-md-6">
<div class="card border-0 shadow-sm">
<img alt="权限管理" class="card-img-top rounded" height="342.42px"
src="https://pure-admin.cn/assets/img/rbac.078e7dea.jpg">
<div class="card-body">
<h5 class="card-title">权限管理</h5>
<p class="card-text">可视化权限配置,角色与资源灵活关联。</p>
</div>
</div>
</div>
@ -465,38 +256,54 @@
</section>
<!-- 页脚 -->
<footer>
<footer class="footer">
<div class="container">
<div class="footer-content">
<div class="footer-column">
<h3>关于 Spring Security</h3>
<p>Spring
Security是一个功能强大且高度可定制的身份验证和访问控制框架是保护基于Spring的应用程序的事实标准。</p>
<div class="social-links">
<a href="#"><i class="fab fa-github"></i></a>
<a href="#"><i class="fab fa-twitter"></i></a>
<a href="#"><i class="fab fa-stack-overflow"></i></a>
</div>
<div class="row">
<div class="col-md-4 mb-4 mb-md-0">
<h5><i class="fas fa-shield-alt me-2"></i>Security Admin</h5>
<p class="small text-white-50">基于Spring Security
6的自定义权限校验后台管理系统为企业级应用提供安全可靠的管理解决方案。</p>
</div>
<div class="footer-column">
<h3>快速链接</h3>
<ul class="footer-links">
<li><a href="#features" target="_blank">核心特性</a></li>
<li><a href="#docs" target="_blank">学习资源</a></li>
<li><a href="/doc.html" target="_blank">API文档</a></li>
<li><a href="/swagger-ui/index.html" target="_blank">Swagger UI</a></li>
<div class="col-md-2 mb-4 mb-md-0">
<h5>快速链接</h5>
<ul class="list-unstyled">
<li><a class="text-white-50" href="#">首页</a></li>
<li><a class="text-white-50" href="/doc.html">API文档</a></li>
<li><a class="text-white-50" href="/swagger-ui/index.html">Swagger UI</a></li>
<li><a class="text-white-50" href="#">GitHub</a></li>
</ul>
</div>
<div class="footer-column">
<h3>联系我们</h3>
<p><i class="fas fa-envelope"></i> security@example.com</p>
<p><i class="fas fa-globe"></i> www.springsecurity.org</p>
<div class="col-md-3 mb-4 mb-md-0">
<h5>技术资源</h5>
<ul class="list-unstyled">
<li><a class="text-white-50" href="https://spring.io/projects/spring-security">Spring Security</a>
</li>
<li><a class="text-white-50" href="https://spring.io/projects/spring-boot">Spring Boot</a></li>
<li><a class="text-white-50" href="https://www.thymeleaf.org/">Thymeleaf</a></li>
</ul>
</div>
<div class="col-md-3">
<h5>联系我</h5>
<ul class="list-unstyled">
<li><i class="fas fa-envelope me-2"></i> <span
class="text-white-50">1319900154@qq.com</span></li>
<li><i class="fas fa-phone me-2"></i> <span class="text-white-50">+86 18900696469</span></li>
</ul>
<div class="mt-3">
<a class="text-white me-3" href="https://github.com/BunnyMaster"><i class="fab fa-github fa-lg"></i></a>
<a class="text-white me-3" href="#"><i class="fab fa-weixin fa-lg"></i></a>
<a class="text-white" href="#"><i class="fab fa-weibo fa-lg"></i></a>
</div>
</div>
</div>
<div class="footer-bottom">
<p>&copy; 2023 Spring Security 学习中心. 保留所有权利.</p>
<hr class="my-4 bg-white-50">
<div class="text-center small text-white-50">
&copy; 2025 Spring Security 6 Admin System. All rights reserved.
</div>
</div>
</footer>
<!-- Bootstrap JS -->
<script th:src="@{/webjars/bootstrap/5.1.3/js/bootstrap.bundle.min.js}"></script>
</body>
</html>

19
pom.xml
View File

@ -49,6 +49,9 @@
<dynamic.datasource.version>4.3.1</dynamic.datasource.version>
<jackson-dataType.version>2.19.0</jackson-dataType.version>
<quartz-scheduler.version>2.3.2</quartz-scheduler.version>
<font-awesome.version>5.15.4</font-awesome.version>
<bootstrap.version>5.1.3</bootstrap.version>
<jquery.version>3.6.0</jquery.version>
</properties>
<dependencyManagement>
@ -164,6 +167,22 @@
<artifactId>quartz</artifactId>
<version>${quartz-scheduler.version}</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>${bootstrap.version}</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>font-awesome</artifactId>
<version>${font-awesome.version}</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>${jquery.version}</version>
</dependency>
</dependencies>
</dependencyManagement>