SpringBoot(二十) Spring Security5 - 快速入门

Spring security 是一个强大的和高度可定制的身份验证和访问控制框架。它是确保基于Spring的应用程序的标准。

前言

Spring Security 为基于javaEE的企业应用程序提供一个全面的解决方案。正如你将从这个参考指南发现的,我们试图为你提供一个有用的并且高度可配置的安全系统。

简介

Spring Security 提供了基于javaEE的企业应有个你软件全面的安全服务。这里特别强调支持使用SPring框架构件的项目,Spring框架是企业软件开发javaEE方案的领导者。如果你还没有使用Spring来开发企业应用程序,我们热忱的鼓励你仔细的看一看。熟悉Spring特别是一来注入原理两帮助你更快更方便的使用Spring Security。

Getting Spring Security

你可以通过几种方式获取Spring Security。你可以从 Spring Security 页面下载一个分发包。从Maven库下载分离的jar文件。另外你也可以从源代码自己编译。

使用Maven

一个最小的SPring Security Maven 依赖通常和下面的类似:

1
2
3
4
5
6
7
8
9
10
11
12
13
<dependencies>
<!-- ... other dependency elements ... -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>{spring-security-version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>{spring-security-version}</version>
</dependency>
</dependencies>

使用Gradle

最小的Gradle一组典型的依赖如下:

1
2
3
4
5
build.gradle
dependencies {
compile 'org.springframework.security:spring-security-web:{spring-security-version}'
compile 'org.springframework.security:spring-security-config:{spring-security-version}'
}

Springboot

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

项目模块

在 Spring Security 3.0, 代码库被分割到单独的jar,这样可以更清楚的分隔不用功能区域和第三方依赖。
注:常用加黑

模块 jar 说明
核心模块 spring-security-core.jar 包含核心的验证和访问控制类和接口,远程支持和基本的配置API。任何使用Spring Security的应用程序都需要这个模块。支持独立应用程序、远程客户端、服务层方法安全和JDBC用户配置。
远程调用 spring-security-remoting.jar 提供与Spring Remoting的集成,通常你不需要这个模块,除非你挣使用Spring Remoting编写远程客户端。
网页 spring-security-web.jar 网站安全相关的基础代码。使用Servlet API的任何应用依赖他。如果你需要Spring Security网页验证服务和基于URL的访问控制你需要这个模块。
配置 spring-security-config.jar 包含安全命令空间的解析代码。如果你使用Spring Security XML命令空间进行配置你需要包含这个模块。
LDAP spring-security-ldap.jar LDAP验证和配置代码,如果你需要使用LDAP验证和管理LDAP用户实体,你需要这个模块。
ACL访问控制表 spring-security-acl.jar ACL专门的领域对象的实现。用来在你的应用程序中应用安全特定的领域对象实例。
CAS spring-security-cas.jar Spring Security的CAS客户端集成。如果你想用CAS的SSO服务器使用Spring Security网页验证需要该模块。
OpenID spring-security-openid.jar OpenID 网页验证支持。使用外部的OpenID服务器验证用户。
Test spring-security-test.jar 支持Spring Security的测试。

Java配置和表单登录

你可能会想知道系统提示您登录表单从哪里来的,因为我们都没有提供任何的HTML或JSP文件。由于Spring Security的默认配置并没有明确设定一个登录页面的URL,Spring Security自动生成一个,基于这个功能被启用,使用默认URL处理登录的提交内容,登录后跳转的URL等等。

Java配置

自动生成的登录页面可以方便应用的快速启动和运行,大多数应用程序都需要提供自己的登录页面。要做到这一点,我们可以更新我们的配置,如下所示:

1
2
3
4
5
6
7
8
9
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login") // 指定登录页的路径
.permitAll(); // 必须允许所有用户访问我们的登录页
}

formLogin().permitAll() 方法允许基于表单登录的所有的URL的所有用户的访问。

表单页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<c:url value="/login" var="loginUrl"/>
<form action="${loginUrl}" method="post"> <!--一个POST请求到/login用来验证用户-->
<c:if test="${param.error != null}"> <!--如果参数有error, 验证尝试失败-->
<p>
Invalid username and password.
</p>
</c:if>
<c:if test="${param.logout != null}"> <!--如果参数有logout, 则登出-->
<p>
You have been logged out.
</p>
</c:if>
<p>
<label for="username">Username</label>
<input type="text" id="username" name="username"/> <!--登录名name必须为username-->
</p>
<p>
<label for="password">Password</label>
<input type="password" id="password" name="password"/> <!--密码name必须为password-->
</p>
<button type="submit" class="btn">Log in</button>
</form>

验证请求

我们的例子中要求用户进行身份验证并且在我们应用程序的每个URL这样做。你可以通过给http.authorizeRequests() 添加多个子节点来指定多个定制需求到我们的URL。

1
2
3
4
5
6
7
8
9
10
11
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests() // 包含多个子节点,每个xxMatchers 按照他们的声明顺序执行
.antMatchers("/resources/**", "/signup", "/about").permitAll() // 任何用户可以访问的URL
.antMatchers("/admin/**").hasRole("ADMIN") // 该URL只能由拥有"ROLE_ADMIN"角色的用户访问
.antMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')") // 该URL只能由同时拥有"ADMIN"和"DBA"角色的用户访问
.anyRequest().authenticated() // 尚未匹配的任何URL要求用户进行身份验证
.and()
// ...
.formLogin();
}

处理登出

当使用WebSecurityConfigurerAdapter, 注销功能会自动应用。默认是访问URL/logout将注销登陆的用户:

  1. 使HTTP Session 无效
  2. 清除所有已经配置的 RememberMe 认证
  3. 清除SecurityContextHolder
  4. 跳转到 /login?logout

和登录功能类似,你也有不同的选项来定制你的注销功能:

1
2
3
4
5
6
7
8
9
10
11
12
protected void configure(HttpSecurity http) throws Exception {
http
.logout() // 提供注销支持
.logoutUrl("/my/logout") // 触发注销操作的URL(默认是`/logout`)
.logoutSuccessUrl("/my/index") // 注销之后跳转的URL页面
.logoutSuccessHandler(logoutSuccessHandler)
.invalidateHttpSession(true) // 注销成功HttpSession无效(默认true)
.addLogoutHandler(logoutHandler)
.deleteCookies(cookieNamesToClear) // 注销成功时将移除的cookie
.and()
...
}

高级验证

到现在为止我们只看了一下基本的验证配置,让我们看看一些稍微高级点的身份验证配置选项。

内存中的身份验证

我们已经看到了一个单用户配置到内存验证的示例,下面是配置多个用户的例子:

1
2
3
4
5
6
7
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER", "ADMIN");
}

JDBC 验证

你可以找一些更新来支持JDBC的验证。下面的例子假设你已经在应用程序中定义好了DataSource 示例提供了一个完整的基于JDBC的验证。

1
2
3
4
5
6
7
8
9
10
11
12
@Autowired
private DataSource dataSource;

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.jdbcAuthentication()
.dataSource(dataSource)
.withDefaultSchema()
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER", "ADMIN");
}

UserDetailsService

你可以通过一个自定义的UserDetailsService 为bean定义自定义身份验证。
例如,下面这个例子假设自定义身份验证SpringDataUserDetailsService实现了UserDetailsService:

1
2
3
4
@Bean
public SpringDataUserDetailsService springDataUserDetailsService() {
return new SpringDataUserDetailsService();
}

你也可以通过让passwordencoder为bean自定义密码如何编码。
例如,如果你使用BCrypt,你可以添加一个bean定义如下图所示:

1
2
3
4
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}

-------------- 本文结束  感谢您的阅读 --------------