1. Spring Security简介
Spring Security 的前身是 Acegi Security,在被收纳为Spring子项目后正式更名为Spring Security。
应用程序的安全性通常体现在两个方面:认证和授权。
- 认证是确认某主体在某系统中是否合法、可用的过程。这里的主体既可以是登录系统的用户,也 可以是接入的设备或者其他系统。
- 授权是指当主体通过认证之后,是否允许其执行某项操作的过程。
这些概念并非Spring Security独有,而是应用安全的基本关注点。Spring Security可以帮助我们更便 捷地完成认证和授权。
Spring Security 支持广泛的认证技术,这些认证技术大多由第三方或相关标准组织开发。Spring Security 已经集成的认证技术如下:
◎ HTTP BASIC authentication headers:一个基于IETF RFC的标准。
◎ HTTP Digest authentication headers:一个基于IETF RFC的标准。
◎ HTTP X.509 client certificate exchange:一个基于IETF RFC的标准。
◎ LDAP:一种常见的跨平台身份验证方式。
◎ Form-based authentication:用于简单的用户界面需求。
◎ OpenID authentication:一种去中心化的身份认证方式。
◎ Authentication based on pre-established request headers:类似于 Computer Associates SiteMinder,一种用户身份验证及授权的集中式安全基础方案。
◎ Jasig Central Authentication Service:单点登录方案。
◎ Transparent authentication context propagation for Remote Method Invocation(RMI) and HttpInvoker:一个Spring远程调用协议。
◎ Automatic "remember-me" authentication:允许在指定到期时间前自行重新登录系统。
◎ Anonymous authentication:允许匿名用户使用特定的身份安全访问资源。
◎ Run-as authentication:允许在一个会话中变换用户身份的机制。
◎ Java Authentication and Authorization Service:JAAS,Java验证和授权API。
◎ Java EE container authentication:允许系统继续使用容器管理这种身份验证方式。
◎ Kerberos:一种使用对称密钥机制,允许客户端与服务器相互确认身份的认证协议。
除此之外,Spring Security还引入了一些第三方包,用于支持更多的认证技术,如JOSSO等。如果 所有这些技术都无法满足需求,则Spring Security允许我们编写自己的认证技术。因此,在绝大部分情 况下,当我们有Java应用安全方面的需求时,选择Spring Security往往是正确而有效的。
在授权上,Spring Security不仅支持基于URL对Web的请求授权,还支持方法访问授权、对象访问授权等,基本涵盖常见的大部分授权场景。
2. 创建项目工程
2.1 修改pom.xml配置文件
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
引入security包后,可以看到自动引入spring-security-web和spring- security -config、spring- security -aop两个核心模块,这正是官方建议引入的Sp ring Security最小依赖
2.2 添加路由
@GetMapping("/")
@ResponseBody
public String test2() {
return "hello , Java技术债务!";
}
2.3 启动工程
访问http://127.0.0.1:8705/
在引入Spring Security项目之后,虽然没有进行任何相关的配置或编码,但Spring Security有一个默 认的运行状态,要求在经过HTTP基本认证后才能访问对应的URL资源,其默认使用的用户名user, 密码则是动态生成并打印到控制台的一串随机码。翻看控制台的打印信息,可以看到
输入用户名和密码后,单击“登录”按钮即可成功访问页面
当然,右HTTP基本认证中,用户名和密码都是可以配置的,最常见的就是在resources下的配置文 件中修改。
spring.security.user.name=1
spring.security.user.password=1
重新启动程序,发现控制台不再打印默认密码串了,此时使用我们自定义的用户名和密码即可登录。
事实上,绝大部分Web应用都不会选择HTTP基本认证这种认证方式,除安全性差、无法携带cookie等因素外,灵活性不足也是它的一个主要缺点。通常大家更愿意选择表单认证,自己实现表单登录页和验证逻辑,从而提高安全性。
3. 自定义表单认证
3.1 创建配置文件
WebSecurityConfig.java
package com.cuizb.cloud.alibaba.gtw.security;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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;
/**
* @author: Java技术债务
* @Date: 2021/6/5 18:45
* Describe: SpringSecurity配置
*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Slf4j
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
public void configure(HttpSecurity http) throws Exception {
log.info("Using de fault configure(HttpSecurity).If subclassed this will potentially override subclass configure(HttpSecurity) .");
http.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.formLogin()
.loginPage("/blog-web/login").permitAll()
.and()
.csrf().disable();
}
}
3.2 HttpSecurity
HttpSecurity实际上对应了Spring Security命名空间配置方式中XML文件内的标签,允许我们为特 定的HTTP请求配置安全策略。
HttpSecurity提供了很多配置相关的方法,分别对应命名空间配置中的子标签
authorizeRequests()方法实际上返回了一个 URL 拦截注册器,我们可以调用它提供的 anyanyRequest()、antMatchers()和regexMatchers()等方法来匹配系统的URL,并为其指定安全 策略。
formLogin()方法和httpBasic()方法都声明了需要Spring Security提供的表单认证方式,分别返 回 对 应 的 配 置 器 。 其 中 , f o r m L o gi n ( ) . l o gi n P a ge ( " / m y L o gi n . h t m l " ) 指 定 自 定 义 的 登 录 页/myLogin.html,同时,Spring Security会用/myLogin.html注册一个POST路由,用于接收登录请求。
csrf()方法是Spring Security提供的跨站请求伪造防护功能,当我们继承 WebSecurityConfigurerAdapter时会默认开启csrf()方法。关于csrf()方法的更多内容会在后面的章节专门探讨,以使测试 进程更加顺利。
3.3 其他表单配置项
package com.cuizb.cloud.alibaba.gtw.security;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* @author: Java技术债务
* @Date: 2021/6/5 18:45
* Describe: SpringSecurity配置
*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Slf4j
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
public void configure(HttpSecurity http) throws Exception {
log.info("Using de fault configure(HttpSecurity).If subclassed this will potentially override subclass configure(HttpSecurity) .");
http.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.formLogin()
.loginPage("/blog-web/login")
.loginProcessingUrl("/blog-web/userLogin")
.successHandler(new UserAuthenticationSuccessHandler())
.failureHandler(new AuthenticationFailureHandler() {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
response.setStatus(401);
PrintWriter writer = response.getWriter();
writer.write("fail");
}
})
.permitAll()
.and()
.csrf().disable();
}
}
表单登录配置模块提供了 successHandler()和 failureHandler()两个方法,分别处理登录成功和 登录失败的逻辑。其中,successHandler()方法带有一个Authentication参数,携带当前登录用户及其角色等信息;而failureHandler()方法携带一个AuthenticationException异常参数。具体处理方式需按照系统的情况自定义。
- 本文作者:
- 原文链接:
- 版权声明: 本博客所有文章除特别声明外,均采用 进行许可。转载请署名作者且注明文章出处。