Springboot整合SpringSecurity
- 一、概述
- 二、快速入门
- 2.1 引入依赖
- 2.2 Application
- 2.3 配置文件
- 2.4 AdminController
- 2.5 简单测试
- 三、进阶使用
- 3.1 引入依赖
- 3.2 示例一
- 3.2.1 SecurityConfig
- 3.2.2 TestController
- 3.3 示例二
- 3.3.1 SecurityConfig2
- 3.3.2 DemoController
- 四、整合 JWT
- 五、项目实践
一、概述
基本上,在所有的开发的系统中,都必须做认证(authentication
)和授权(authorization
),以保证系统的安全性。
以论坛举例子:
【认证】你要登陆论坛,输入用户名张三,密码 1234,密码正确,证明你张三确实是张三,这就是 authentication。
【授权】再一 check 用户张三是个版主,所以有权限加精删别人帖,这就是 authorization 。
二、快速入门
2.1 引入依赖
<!-- 实现对 Spring MVC 的自动化配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 实现对 Spring Security 的自动化配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
2.2 Application
创建 Application.java
类,配置 @SpringBootApplication
注解 :
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}
2.3 配置文件
在 application.yml
中,添加 Spring Security 配置 :
spring:
# Spring Security 配置项,对应 SecurityProperties 配置类
security:
# 配置默认的 InMemoryUserDetailsManager 的用户账号与密码。
user:
name: user # 账号
password: user # 密码
roles: ADMIN # 拥有角色
- 在
spring.security
配置项,设置 Spring Security 的配置,对应 SecurityProperties 配置类。 - 默认情况下,Spring Boot UserDetailsServiceAutoConfiguration 自动化配置类,会创建一个内存级别的 InMemoryUserDetailsManager Bean 对象,提供认证的用户信息。
- 这里,添加了
spring.security.user
配置项,UserDetailsServiceAutoConfiguration 会基于配置的信息创建一个用户 user 在内存中。 - 如果,我们未添加
spring.security.user
配置项,UserDetailsServiceAutoConfiguration 会自动创建一个用户名为"user"
,密码为 UUID 随机的用户 User 在内存中。
2.4 AdminController
AdminController
类,提供管理员 API
接口 :
@RestController
@RequestMapping("/admin")
public class AdminController {
@GetMapping("/demo")
public String demo() {
return "示例返回";
}
}
2.5 简单测试
项目启动成功后,浏览器访问 http://127.0.0.1:8080/admin/demo
接口。因为未登陆,所以被 Spring Security
拦截到登陆界面 :
三、进阶使用
3.1 引入依赖
3.2 示例一
自定义 Spring Security
的配置,实现权限控制。
3.2.1 SecurityConfig
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
// <X> 使用内存中的 InMemoryUserDetailsManager
.inMemoryAuthentication()
// <Y> 不使用 PasswordEncoder 密码编码器
.passwordEncoder(NoOpPasswordEncoder.getInstance())
// <Z> 配置 admin 用户
.withUser("admin").password("admin").roles("ADMIN")
// <Z> 配置 normal 用户
.and().withUser("normal").password("normal").roles("NORMAL");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
// <M> 配置请求地址的权限
.authorizeRequests()
// 所有用户可访问
.antMatchers("/test/echo").permitAll()
// 需要 ADMIN 角色
.antMatchers("/test/admin").hasRole("ADMIN")
// 需要 NORMAL 角色
.antMatchers("/test/normal").access("hasRole('ROLE_NORMAL')")
// 任何请求,访问的用户都需要经过认证
.anyRequest().authenticated()
.and()
// <N> 设置 Form 表单登陆
.formLogin()
// 登陆 URL 地址 所有用户可访问
//.loginPage("/login")
.permitAll()
.and()
// 配置退出相关
.logout()
//退出 URL 地址 所有用户可访问
//.logoutUrl("/logout")
.permitAll();
}
}
<x>
处,调用inMemoryAuthentication()
方法,使用内存级别的 InMemoryUserDetailsManager Bean 对象,提供认证的用户信息。
- Spring 内置了两种 UserDetailsManager 实现:
- InMemoryUserDetailsManager 。
- JdbcUserDetailsManager ,基于 JDBC的 JdbcUserDetailsManager 。
- 实际项目中,更多采用调用
userDetailsService(userDetailsService)
方法,使用自定义实现的 UserDetailsService 实现类,更加灵活且自由的实现认证的用户信息的读取。
<Y>
处,调用passwordEncoder(passwordEncoder)
方法,设置 PasswordEncoder 密码编码器。
- 在这里,为了方便,我们使用 NoOpPasswordEncoder 。实际上,等于不使用 PasswordEncoder ,不配置的话会报错。
- 生产环境下,推荐使用 BCryptPasswordEncoder 。
<Z>
处,配置了「admin/admin」和「normal/normal」两个用户,分别对应 ADMIN 和 NORMAL 角色。<M>
处,调用authorizeRequests()
方法,开始配置 URL 的权限控制。
-
#(String... antPatterns)
方法,配置匹配的 URL 地址,基于 Ant 风格路径表达式 ,可传入多个。 - 【常用】
#permitAll()
方法,所有用户可访问。 - 【常用】
#denyAll()
方法,所有用户不可访问。 - 【常用】
#authenticated()
方法,登陆用户可访问。 -
#anonymous()
方法,无需登陆,即匿名用户可访问。 -
#rememberMe()
方法,通过 remember me 登陆的用户可访问。 -
#hasIpAddress(String ipaddressExpression)
方法,来自指定 IP 表达式的用户可访问。 - 【常用】
#hasRole(String role)
方法, 拥有指定角色的用户可访问。 - 【常用】
#hasAnyRole(String... roles)
方法,拥有指定任一角色的用户可访问。 - 【常用】
#hasAuthority(String authority)
方法,拥有指定权限(authority
)的用户可访问。 - 【常用】
#hasAuthority(String... authorities)
方法,拥有指定任一权限(authority
)的用户可访问。 - 【最牛】
#access(String attribute)
方法,当 Spring EL 表达式的执行结果为true
时,可以访问。
<N>
处,调用formLogin()
方法,设置 Form 表单登陆 。
- 如果想要自定义登陆页面,可以通过
#loginPage(String loginPage)
方法,来进行设置。 - 如果想要自定义退出页面,可以通过
#logoutUrl(String logoutUrl)
方法,来进行设置。
3.2.2 TestController
@RestController
@RequestMapping("/test")
public class TestController {
@GetMapping("/echo")
public String demo() {
return "示例返回";
}
@GetMapping("/home")
public String home() {
return "我是首页";
}
@GetMapping("/admin")
public String admin() {
return "我是管理员";
}
@GetMapping("/normal")
public String normal() {
return "我是普通用户";
}
}
- 对于
/test/echo
接口,直接访问,无需登陆。 - 对于
/test/home
接口,无法直接访问,需要进行登陆。 - 对于
/test/admin
接口,需要登陆「admin/admin
」用户,因为需要ADMIN
角色。 - 对于
/test/normal
接口,需要登陆「normal/normal
」用户,因为需要NORMAL
角色。
登陆「normal/normal
」用户后,去访问 /test/admin
接口,会返回 403 界面,无权限~
3.3 示例二
使用 Spring Security
的注解,实现权限控制。
3.3.1 SecurityConfig2
增加 @EnableGlobalMethodSecurity 注解,开启对 SpringSecurity
注解的方法,进行权限验证。
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig2 {
}
3.3.2 DemoController
@RestController
@RequestMapping("/demo")
public class DemoController {
@PermitAll
@GetMapping("/echo")
public String demo() {
return "示例返回";
}
@GetMapping("/home")
public String home() {
return "我是首页";
}
@PreAuthorize("hasRole('ROLE_ADMIN')")
@GetMapping("/admin")
public String admin() {
return "我是管理员";
}
@PreAuthorize("hasRole('ROLE_NORMAL')")
@GetMapping("/normal")
public String normal() {
return "我是普通用户";
}
}
- @PermitAll 注解,等价于
#permitAll()
方法,所有用户可访问。
- 重要!因为在 SecurityConfig中,配置了
.anyRequest().authenticated()
,任何请求,访问的用户都需要经过认证。所以这里@PermitAll
注解实际是不生效的。也就是说,Java Config
配置的权限,和注解配置的权限,两者是叠加的。
- @PreAuthorize 注解,等价于
#access(String attribute)
方法,,当Spring EL
表达式的执行结果为true
时,可以访问。
四、整合 JWT
五、项目实践