跳到主要内容
Spring Security 入门:概念、认证与授权配置 | 极客日志
Java java
Spring Security 入门:概念、认证与授权配置 介绍 Spring Security 框架的核心功能、架构设计及配置方式。涵盖快速入门案例,包括环境准备与依赖整合。详细讲解认证操作,如自定义登录页面、关闭 CSRF 拦截、数据库认证、密码加密及记住我功能。同时阐述授权机制,包括注解使用(JSR250、Spring 表达式、Secured)和标签使用,帮助开发者构建安全的 Java Web 应用。
竹影清风 发布于 2026/3/27 更新于 2026/6/1 36 浏览Spring Security
Spring Security 是一个功能强大且高度可配置的安全框架,用于为 Java 应用程序提供身份验证和授权功能。以下是对它的详细介绍:
核心功能
身份验证 :支持多种身份验证方式,如用户名 / 密码、OAuth、LDAP 等。可以方便地与各种身份验证源集成,如数据库、LDAP 目录、OAuth 提供商等。例如,在一个 Web 应用中,用户可以通过输入用户名和密码进行登录,Spring Security 会验证用户提供的凭据是否有效。
授权 :提供了细粒度的授权控制,可以基于角色、权限或自定义的访问规则来限制对资源的访问。比如,只有具有特定角色(如管理员)的用户才能访问某些敏感的 API 端点或页面。
防止常见攻击 :自动防范常见的安全漏洞,如跨站请求伪造(CSRF)、会话固定攻击、点击劫持等。
架构设计
过滤器链 :Spring Security 基于 Servlet 过滤器链实现,通过一系列的过滤器来处理安全相关的任务,如身份验证、授权、安全上下文管理等。每个过滤器都有特定的职责,它们协同工作以确保应用程序的安全性。
安全上下文 :安全上下文(Security Context)用于存储当前用户的安全信息,如用户身份、角色和权限等。在整个应用程序的执行过程中,不同的组件可以通过安全上下文来获取当前用户的相关信息,以便进行授权决策和其他安全相关的操作。
配置方式
Java 配置 :通过 Java 代码进行配置,提供了一种类型安全、可维护的方式来定义安全规则和配置。例如,可以使用 @Configuration 和 @EnableWebSecurity 注解来创建一个 Spring Security 配置类,然后在类中定义各种安全配置方法。
XML 配置 :使用 XML 文件来配置 Spring Security,这种方式在一些传统的企业级应用中较为常见。通过在 XML 文件中定义 Bean 和配置元素,可以指定身份验证提供者、授权规则、过滤器等安全相关的配置。
与其他框架集成
Spring Boot :Spring Security 与 Spring Boot 无缝集成,通过自动配置和起步依赖,可以快速搭建安全的 Spring Boot 应用。在 Spring Boot 应用中,只需添加相关的依赖,然后进行简单的配置,就可以启用 Spring Security 的功能。
Spring MVC :与 Spring MVC 紧密集成,能够方便地对 Web 应用的控制器方法进行安全控制。可以在控制器方法上使用 @PreAuthorize、@PostAuthorize 等注解来定义访问权限,确保只有授权的用户才能访问相应的方法。
社区支持和资源
活跃的社区 :Spring Security 拥有庞大且活跃的社区,这意味着在使用过程中遇到问题时,很容易在社区论坛、Stack Overflow 等平台上找到解决方案。同时,社区也会不断地为框架的发展做出贡献,推动其功能的不断完善和更新。
丰富的文档 :官方提供了详细的文档,包括用户指南、API 文档等,有助于开发者快速上手和深入了解框架的各种功能。此外,还有许多第三方的书籍、博客和教程可供参考,进一步帮助开发者掌握 Spring Security 的使用。
SpringSecurity 的初次邂逅
1. Spring Security 概念
Spring Security 是 Spring 采用 AOP 思想,基于 servlet 过滤器实现的安全框架。它提供了完善的认证机制和方法级的授权功能。是一款非常优秀的权限管理框架。
Spring Security 是一个功能强大且高度可定制的身份验证和访问控制框架。它是用于保护基于 Spring 的应用程序的事实上的标准。
Spring Security 是一个框架,致力于为 Java 应用程序提供身份验证和授权。像所有 Spring 项目一样,Spring Security 的真正强大之处在于它可以轻松扩展以满足定制需求的能力。
特征
保护免受会话固定,点击劫持,跨站点请求伪造等攻击
Servlet API 集成
与 Spring Web MVC 的可选集成
1.2 快速入门案例
1.2.1 环境准备 我们准备一个 SpringMVC+Spring+jsp 的 Web 环境,然后在这个基础上整合 SpringSecurity。
<dependencies >
<dependency >
<groupId > junit</groupId >
<artifactId > junit</artifactId >
<version > 4.11</version >
<scope > test</scope >
</dependency >
<dependency >
<groupId > org.springframework</groupId >
<artifactId > spring-webmvc</artifactId >
<version > 5.2.1.RELEASE</version >
</dependency >
<dependency >
<groupId > javax.servlet</groupId >
<artifactId > servlet-api</artifactId >
<version > 2.5</version >
<scope > provided</scope >
</dependency >
<dependency >
<groupId > org.slf4j</groupId >
<artifactId > slf4j-log4j12</artifactId >
<version > 1.7.25</version >
</dependency >
</dependencies >
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns ="http://www.springframework.org/schema/beans"
xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context ="http://www.springframework.org/schema/context"
xsi:schemaLocation ="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd" >
<context:component-scan base-package ="com.bobo.service" > </context:component-scan >
</beans >
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns ="http://www.springframework.org/schema/beans"
xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context ="http://www.springframework.org/schema/context"
xmlns:mvc ="http://www.springframework.org/schema/mvc"
xsi:schemaLocation ="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd" >
<context:component-scan base-package ="com.bobo.controller" > </context:component-scan >
<mvc:annotation-driven > </mvc:annotation-driven >
</beans >
log4j.rootCategory=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[QC] %p [%t] %C.%M(%L) | %m%n
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app version ="2.5" xmlns ="http://java.sun.com/xml/ns/javaee"
xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation ="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" >
<display-name > Archetype Created Web Application</display-name >
<context-param >
<param-name > contextConfigLocation</param-name >
<param-value > classpath:applicationContext.xml</param-value >
</context-param >
<listener >
<listener-class > org.springframework.web.context.ContextLoaderListener</listener-class >
</listener >
<filter >
<filter-name > CharacterEncodingFilter</filter-name >
<filter-class > org.springframework.web.filter.CharacterEncodingFilter</filter-class >
<init-param >
<param-name > encoding</param-name >
<param-value > utf-8</param-value >
</init-param >
</filter >
<filter-mapping >
<filter-name > CharacterEncodingFilter</filter-name >
<url-pattern > /*</url-pattern >
</filter-mapping >
<servlet >
<servlet-name > dispatcherServletb</servlet-name >
<servlet-class > org.springframework.web.servlet.DispatcherServlet</servlet-class >
<init-param >
<param-name > contextConfigLocation</param-name >
<param-value > classpath:spring-mvc.xml</param-value >
</init-param >
<load-on-startup > 1</load-on-startup >
</servlet >
<servlet-mapping >
<servlet-name > dispatcherServletb</servlet-name >
<url-pattern > /</url-pattern >
</servlet-mapping >
</web-app >
<plugins >
<plugin >
<groupId > org.apache.tomcat.maven</groupId >
<artifactId > tomcat7-maven-plugin</artifactId >
<version > 2.2</version >
<configuration >
<port > 8082</port >
<path > /</path >
</configuration >
</plugin >
</plugins >
1.2.2 整合 SpringSecurity spring-security-core.jar 核心包,任何 SpringSecurity 的功能都需要此包
spring-security-web.jar:web 工程必备,包含过滤器和相关的 web 安全的基础结构代码
spring-security-config.jar:用于 xml 文件解析处理
spring-security-tablibs.jar:动态标签库
<dependency >
<groupId > org.springframework.security</groupId >
<artifactId > spring-security-config</artifactId >
<version > 5.1.5.RELEASE</version >
</dependency >
<dependency >
<groupId > org.springframework.security</groupId >
<artifactId > spring-security-taglibs</artifactId >
<version > 5.1.5.RELEASE</version >
</dependency >
web.xml 文件中配置 SpringSecurity
<filter >
<filter-name > springSecurityFilterChain</filter-name >
<filter-class > org.springframework.web.filter.DelegatingFilterProxy</filter-class >
</filter >
<filter-mapping >
<filter-name > springSecurityFilterChain</filter-name >
<url-pattern > /*</url-pattern >
</filter-mapping >
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns ="http://www.springframework.org/schema/beans"
xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security ="http://www.springframework.org/schema/security"
xsi:schemaLocation ="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd" >
<security:http auto-config ="true" use-expressions ="true" >
<security:intercept-url pattern ="/**" access ="hasAnyRole('ROLE_USER')" > </security:intercept-url >
</security:http >
<security:authentication-manager >
<security:authentication-provider >
<security:user-service >
<security:user name ="zhangsan" authorities ="ROLE_USER" password ="{noop}123" > </security:user >
<security:user name ="lisi" authorities ="ROLE_USER" password ="{noop}123456" > </security:user >
</security:user-service >
</security:authentication-provider >
</security:authentication-manager >
</beans >
将 SpringSecurity 的配置文件引入到 Spring 中
2. 认证操作
2.1 自定义登录页面 <%-- Created by IntelliJ IDEA. --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>登录页面</h1>
<form action="/login" method="post" >
账号:<input type="text" name="username" ><br>
密码:<input type="password" name="password" ><br>
<input type="submit" value="登录" >
</form>
</body>
</html>
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns ="http://www.springframework.org/schema/beans"
xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security ="http://www.springframework.org/schema/security"
xsi:schemaLocation ="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd" >
<security:http auto-config ="true" use-expressions ="true" >
<security:intercept-url pattern ="/login.jsp" access ="permitAll()" />
<security:intercept-url pattern ="/**" access ="hasAnyRole('ROLE_USER')" />
<security:form-login login-page ="/login.jsp"
login-processing-url ="/login"
default-target-url ="/home.jsp"
authentication-failure-url ="/error.jsp"
/>
<security:logout logout-url ="/logout"
logout-success-url ="/login.jsp" />
</security:http >
<security:authentication-manager >
<security:authentication-provider >
<security:user-service >
<security:user name ="zhangsan" authorities ="ROLE_USER" password ="{noop}123" > </security:user >
<security:user name ="lisi" authorities ="ROLE_USER" password ="{noop}123456" > </security:user >
</security:user-service >
</security:authentication-provider >
</security:authentication-manager >
</beans >
访问 home.jsp 页面后会自动跳转到自定义的登录页面,说明这个需求是实现了
2.2 关闭 CSRF 拦截 为什么系统默认的登录页面提交没有 CRSF 拦截的问题呢
我自定义的认证页面没有这个信息怎么办呢?两种方式:
2.3 数据库认证 前面的案例我们的账号信息是直接写在配置文件中的,这显然是不太好的,我们来介绍小如何实现和数据库中的信息进行认证
<dependency >
<groupId > org.mybatis</groupId >
<artifactId > mybatis</artifactId >
<version > 3.5.4</version >
</dependency >
<dependency >
<groupId > org.mybatis</groupId >
<artifactId > mybatis-spring</artifactId >
<version > 2.0.4</version >
</dependency >
<dependency >
<groupId > mysql</groupId >
<artifactId > mysql-connector-java</artifactId >
<version > 8.0.11</version >
</dependency >
<dependency >
<groupId > com.alibaba</groupId >
<artifactId > druid</artifactId >
<version > 1.1.8</version >
</dependency >
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/logistics?characterEncoding=utf-8&serverTimezone=UTC
jdbc.username=root
jdbc.password=123456
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns ="http://www.springframework.org/schema/beans"
xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context ="http://www.springframework.org/schema/context"
xsi:schemaLocation ="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd" >
<context:component-scan base-package ="com.bobo.service" > </context:component-scan >
<import resource ="classpath:spring-security.xml" />
<context:property-placeholder location ="classpath:db.properties" />
<bean >
<property name ="url" value ="${jdbc.url}" />
<property name ="driverClassName" value ="${jdbc.driver}" />
<property name ="username" value ="${jdbc.username}" />
<property name ="password" value ="${jdbc.password}" />
</bean >
<bean >
<property name ="dataSource" ref ="dataSource" />
<property name ="configLocation" value ="classpath:mybatis-config.xml" />
<property name ="mapperLocations" value ="classpath:mapper/*.xml" />
</bean >
<bean >
<property name ="basePackage" value ="com.bobo.mapper" />
</bean >
</beans >
需要完成认证的 service 中继承 UserDetailsService 父接口
package com.bobo.service.impl;
import com.bobo.mapper.UserMapper;
import com.bobo.pojo.User;
import com.bobo.pojo.UserExample;
import com.bobo.service.IUserService;
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.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class UserServiceImpl implements IUserService {
@Autowired
private UserMapper mapper;
@Override
public UserDetails loadUserByUsername (String s) throws UsernameNotFoundException {
UserExample example = new UserExample ();
example.createCriteria().andUserNameEqualTo(s);
List<User> users = mapper.selectByExample(example);
if (users != null && users.size() > 0 ){
User user = users.get(0 );
if (user != null ){
List<SimpleGrantedAuthority> authorities = new ArrayList <>();
authorities.add(new SimpleGrantedAuthority ("ROLE_USER" ));
UserDetails userDetails = new org .springframework.security.core.userdetails.User(
user.getUserName(),"{noop}" +user.getPassword(),authorities
);
return userDetails;
}
}
return null ;
}
}
最后修改配置文件关联我们自定义的 service 即可
2.4 加密 在 SpringSecurity 中推荐我们是使用的加密算法是 BCryptPasswordEncoder
2.5 认证状态 用户的状态包括 是否可用,账号过期,凭证过期,账号锁定等等。
我们可以在用户的表结构中添加相关的字段来维护这种关系
2.6 记住我 在 SpringSecurity 中默认是关闭 RememberMe 功能的,我们需要放开
记住我的功能会方便大家的使用,但是安全性却是令人担忧的,因为 Cookie 信息存储在客户端很容易被盗取,这时我们可以将这些数据持久化到数据库中。
CREATE TABLE `persistent_logins` (
`username` VARCHAR (64 ) NOT NULL ,
`series` VARCHAR (64 ) NOT NULL ,
`token` VARCHAR (64 ) NOT NULL ,
`last_used` TIMESTAMP NOT NULL ,
PRIMARY KEY (`series`)
) ENGINE = INNODB DEFAULT CHARSET = utf8
注意设置了过期时间,到期后并不是删除表结构中的数据,而是客户端不会在携带相关信息了,同时删除掉数据库中的数据 记住我 也会失效
3. 授权
3.1 注解使用 <?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns ="http://www.springframework.org/schema/beans"
xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context ="http://www.springframework.org/schema/context"
xmlns:mvc ="http://www.springframework.org/schema/mvc"
xmlns:security ="http://www.springframework.org/schema/security"
xsi:schemaLocation ="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd" >
<context:component-scan base-package ="com.bobo.controller" > </context:component-scan >
<mvc:annotation-driven > </mvc:annotation-driven >
<security:global-method-security
jsr250-annotations ="enabled"
pre-post-annotations ="enabled"
secured-annotations ="enabled"
/>
</beans >
<dependency >
<groupId > javax.annotation</groupId >
<artifactId > jsr250-api</artifactId >
<version > 1.0</version >
</dependency >
package com.bobo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.annotation.security.RolesAllowed;
@Controller
@RequestMapping("/user")
public class UserController {
@RolesAllowed(value = {"ROLE_ADMIN"})
@RequestMapping("/query")
public String query () {
System.out.println("用户查询...." );
return "/home.jsp" ;
}
@RolesAllowed(value = {"ROLE_USER"})
@RequestMapping("/save")
public String save () {
System.out.println("用户添加...." );
return "/home.jsp" ;
}
@RequestMapping("/update")
public String update () {
System.out.println("用户更新...." );
return "/home.jsp" ;
}
}
package com.bobo.controller;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.annotation.security.RolesAllowed;
@Controller
@RequestMapping("/order")
public class OrderController {
@PreAuthorize(value = "hasAnyRole('ROLE_USER')")
@RequestMapping("/query")
public String query () {
System.out.println("用户查询...." );
return "/home.jsp" ;
}
@PreAuthorize(value = "hasAnyRole('ROLE_ADMIN')")
@RequestMapping("/save")
public String save () {
System.out.println("用户添加...." );
return "/home.jsp" ;
}
@RequestMapping("/update")
public String update () {
System.out.println("用户更新...." );
return "/home.jsp" ;
}
}
package com.bobo.controller;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/role")
public class RoleController {
@Secured("ROLE_USER")
@RequestMapping("/query")
public String query () {
System.out.println("用户查询...." );
return "/home.jsp" ;
}
@Secured("ROLE_ADMIN")
@RequestMapping("/save")
public String save () {
System.out.println("用户添加...." );
return "/home.jsp" ;
}
@RequestMapping("/update")
public String update () {
System.out.println("用户更新...." );
return "/home.jsp" ;
}
}
新增一个错误页面,然后在 SpringSecurity 的配置文件中配置即可
当然你也可以使用前面介绍的 SpringMVC 中的各种异常处理器处理
3.2 标签使用 前面介绍的注解的权限管理可以控制用户是否具有这个操作的权限,但是当用户具有了这个权限后进入到具体的操作页面,这时我们还有进行更细粒度的控制,这时注解的方式就不太适用了,这时我们可以通过标签来处里
<%-- Created by IntelliJ IDEA. --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="security" uri="http://www.springframework.org/security/tags" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>欢迎光临...</h1>
<security:authentication property="principal.username" />
<security:authorize access="hasAnyRole('ROLE_USER')" >
<a href="#" >用户查询</a><br>
</security:authorize>
<security:authorize access="hasAnyRole('ROLE_ADMIN')" >
<a href="#" >用户添加</a><br>
</security:authorize>
<security:authorize access="hasAnyRole('ROLE_USER')" >
<a href="#" >用户更新</a><br>
</security:authorize>
<security:authorize access="hasAnyRole('ROLE_ADMIN')" >
<a href="#" >用户删除</a><br>
</security:authorize>
</body>
</html>
相关免费在线工具 Keycode 信息 查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
Escape 与 Native 编解码 JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
JavaScript / HTML 格式化 使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
JavaScript 压缩与混淆 Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online