SpringSecurity配合Thymeleaf实现详解,以及实战用例

目录

Spring Security介绍

Spring Security的核心功能:

配合Thymeleaf的Spring Security用法解析

1. 引入Spring Security和Thymeleaf依赖

2. 配置Spring Security

3. Thymeleaf与Spring Security标签

4. Spring Security表单认证

5. 示例:登录页面与权限控制

SpringBoot+Thymeleaf完成安全认证,登录登出操作。


Spring Security介绍

Spring Security是一个强大的认证和授权框架,用于保护基于Spring的应用程序。它提供了全面的安全功能,包括认证、授权、攻击防护等,能够有效地帮助开发者构建安全的Web应用程序。

Spring Security的核心功能:

        1.认证(Authentication)

  • 用于确认用户身份,常见的认证方式有用户名密码、OAuth、LDAP等。
  • Spring Security支持多种身份验证机制,如基于表单的认证、HTTP基本认证等。

        2.授权(Authorization)

  • 用于确定用户是否有权限访问特定资源或操作。
  • 可以基于角色、权限进行细粒度的控制,也可以根据访问路径、HTTP方法进行安全控制。

        3.CSRF防护:

  • Spring Security内置了对跨站请求伪造(CSRF)攻击的防护。

        4.会话管理

  • 提供会话固定 Fixation)防护和并发会话控制。攻击(Session)

        5.密码加密:

  • 提供了多种密码加密方式,常用的如BCrypt、PBKDF2等。

        6.自定义过滤器

  • 可以在Spring Security的过滤链中插入自定义过滤器,满足业务需求。

配合Thymeleaf的Spring Security用法解析

Thymeleaf是一个流行的Java模板引擎,广泛用于Web应用程序中构建动态内容。与Spring Security结合使用时,Thymeleaf可以通过其springSecurity命名空间来帮助处理与安全相关的元素。

1. 引入Spring Security和Thymeleaf依赖

pom.xml中添加以下依赖:

<dependencies>
    <!-- Spring Security -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    
    <!-- Spring Thymeleaf -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    
    <!-- Spring Security Thymeleaf -->
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-taglibs</artifactId>
    </dependency>
</dependencies>
2. 配置Spring Security

在Spring Boot中,可以通过application.properties或者application.yml来配置Spring Security的基础功能。

# 禁用默认的登录页面
spring.security.form.login.enabled=false
# 自定义登录页面URL
spring.security.form.login.login-page=/login
3. Thymeleaf与Spring Security标签

在Thymeleaf模板中,可以使用Spring Security提供的标签来进行权限控制、条件判断等。

登录表单:通过<form>和Spring Security的标签,可以创建一个登录表单。

<form th:action="@{/login}" method="post">
    <div>
        <label for="username">Username:</label>
        <input type="text" name="username" id="username" required="required"/>
    </div>
    <div>
        <label for="password">Password:</label>
        <input type="password" name="password" id="password" required="required"/>
    </div>
    <div>
        <button type="submit">Login</button>
    </div>
</form>

授权控制:使用sec:authorize标签来控制某些元素的可见性或执行的条件。

<div sec:authorize="isAuthenticated()">
    <!-- 只有已认证用户才能看到的内容 -->
    <p>Welcome, authenticated user!</p>
</div>

<div sec:authorize="hasRole('ADMIN')">
    <!-- 只有ADMIN角色用户能看到的内容 -->
    <p>Admin dashboard</p>
</div>

退出登录:通过Thymeleaf与Spring Security集成,可以创建一个退出登录的链接。

<a sec:authorize="isAuthenticated()" href="/logout">Logout</a>
4. Spring Security表单认证

Spring Security提供了一些基本的配置来启用基于表单的认证。可以在配置类中自定义登录页面、注销页面、登录失败和成功的处理等。

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/login", "/css/**", "/js/**").permitAll()  // 允许所有人访问登录页面和静态资源
                .anyRequest().authenticated()  // 其他页面需要认证
            .and()
            .formLogin()
                .loginPage("/login")  // 自定义登录页面
                .permitAll()
            .and()
            .logout()
                .permitAll();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 配置内存中的用户和角色
        auth.inMemoryAuthentication()
            .withUser("user").password(passwordEncoder().encode("password")).roles("USER")
            .and()
            .withUser("admin").password(passwordEncoder().encode("admin")).roles("ADMIN");
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}
5. 示例:登录页面与权限控制

创建一个简单的登录页面login.html,通过Spring Security控制访问权限:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
<head>
    <title>Login</title>
</head>
<body>
    <h1>Login</h1>
    <form action="#" th:action="@{/login}" method="post">
        <div>
            <label for="username">Username:</label>
            <input type="text" name="username" id="username" />
        </div>
        <div>
            <label for="password">Password:</label>
            <input type="password" name="password" id="password" />
        </div>
        <button type="submit">Login</button>
    </form>
    <div sec:authorize="isAuthenticated()">
        <p>You are logged in!</p>
    </div>
</body>
</html>

SpringBoot+Thymeleaf完成安全认证,登录登出操作。

1.导入Maven坐标

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

    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-config</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.3.31</version>
</dependency>

2.AuthInterceptor拦截器

package com.book.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class AuthInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) throws Exception {
        HttpSession session = request.getSession(false);

        // 排除登录、注册等公开页面
        String uri = request.getRequestURI();
        if (uri.startsWith("/user/login") || uri.startsWith("/user/register") ||
                uri.startsWith("/static/") || uri.equals("/")) {
            return true;
        }

        // 检查session中的用户信息
        if (session == null || session.getAttribute("user") == null) {
            response.sendRedirect("/user/login");
            return false;
        }
        return true;
    }
}

3.WebConfig注册拦截器

package com.book.config;
import com.book.interceptor.AuthInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@Slf4j
public class WebConfig implements WebMvcConfigurer {
    /**
     * 注册自定义拦截器
     *
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new AuthInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns(
                        "/user/login",
                        "/user/register",
                        "/css/**",
                        "/js/**",
                        "/error"
                );
    }
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        // 映射本地文件系统到 "/uploads/**"
        registry.addResourceHandler("/uploads/**")
                .addResourceLocations("file:///F:/SpringBoot/libraryManagement/uploads/");
    }
}

4.SecurityConfig安全配置

package com.book.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/user/login", "/user/register", "/css/**","/js/**").permitAll()
                .anyRequest().authenticated()
                .and()
                // 完全禁用Spring Security的表单登录
                .formLogin().disable()
                // 禁用默认的/logout处理
                .logout().disable()
                .csrf()
                .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
                .and()
                .sessionManagement()
                .sessionFixation().migrateSession()
                .maximumSessions(1)
                .maxSessionsPreventsLogin(false)
                .expiredUrl("/user/login?expired=true");
    }
}

5.Controller-登录登出操作

登录成功后重定向至book/list

@PostMapping("/login")
public String handleLogin(@RequestParam String username,
                          @RequestParam String password,
                          HttpSession session) {
    log.info("登录请求 - username: {}", username);

    User loginUser = userService.getUserByUsername(username);
    if (loginUser == null || !HashUtils.verifyPassword(password, loginUser.getPassword(), loginUser.getSalt())) {
        return "redirect:/user/login?error=true";
    }

    // 1. 设置session
    session.setAttribute("user", loginUser);

    // 2. 设置Spring Security认证上下文(关键)
    Authentication auth = new UsernamePasswordAuthenticationToken(
            loginUser.getUsername(),
            null,
            Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER")) // 假设所有用户都有USER角色
    );
    SecurityContextHolder.getContext().setAuthentication(auth);

    return "redirect:/book/list";
}


//登出操作,使session事物失效
@GetMapping("/logout")
public String logout(HttpSession session) {
    session.invalidate();
    return "redirect:/user/login";
}

6.login.html用户登录页面

ps:表单一定要包含这部分

​​​​​​​<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/>
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>用户登录</title>
    <link rel="stylesheet" th:href="@{/css/bootstrap.min.css}"/>
</head>
<body>
<div class="container mt-5">
    <div class="row justify-content-center">
        <div class="col-md-6 col-lg-4">
            <div class="card shadow">
                <div class="card-body">
                    <h3 class="card-title text-center mb-4">用户登录</h3>

                    <!-- 错误消息 -->
                    <div th:if="${errorMsg}" class="alert alert-danger" th:text="${errorMsg}"></div>

                    <!-- 传统表单提交到自定义Controller -->
                    <form th:action="@{/user/login}" method="post">
                        <input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/>

                        <div class="mb-3">
                            <label for="username" class="form-label">用户名</label>
                            <input type="text" class="form-control" id="username" name="username" required>
                        </div>
                        <div class="mb-3">
                            <label for="password" class="form-label">密码</label>
                            <input type="password" class="form-control" id="password" name="password" required>
                        </div>
                        <div class="d-grid gap-2">
                            <button type="submit" class="btn btn-primary">登录</button>
                        </div>
                    </form>

                    <div class="mt-3 text-center">
                        <a th:href="@{/user/register}" class="text-decoration-none">还没有账号?立即注册</a>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
</body>
</html>

总结

Spring Security和Thymeleaf结合使用,可以轻松地在Web应用中实现认证和授权功能。通过Spring Security的标签(如sec:authorize)和Thymeleaf的模板引擎,可以在页面中实现动态的权限控制、用户认证等操作,增强了Web应用的安全性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值