SpringBoot SpringSecurity JWT实现系统安全策略详解
1. 什么是JWT
JWT(JSON Web Token)是一种用于认证的开放标准。可以基于HTTP协议上的Bearer认证方式对用户进行身份验证和授权。JWT由三部分组成:头部、载荷以及签名。
头部:包含了加密算法、哪种类型的token(例如,Bearer),可以使用什么类型的算法来进行加密等信息。
载荷:是存放有效信息的地方,可以自定义信息字段,例如用户id、登陆时间、有效期等。
签名:是第三段,主要用来验证上面两部分的合法性,保证信息不会被篡改。
2. 为何选择SpringBoot SpringSecurity JWT
SpringBoot是一个非常流行的Java Web开发框架,通过SpringBoot开发一个Web应用非常容易、便捷、高效。
而SpringSecurity是Spring提供的一个安全框架,它实现了许多常用的安全功能,如权限设置、身份认证等,使用SpringSecurity能为应用程序提供安全支持,保证应用程序的安全性。
使用JWT认证,能够实现无状态的验证,不需要在服务器端保存Session,有效攻击防御XSS、CSRF、SQL Injection等常见的攻击。
3. JWT实现系统安全策略步骤
- 引入SpringBoot、SpringSecurity和JWT依赖
在使用SpringBoot开发一个应用程序时,可以添加对应的依赖来简化操作。首先在pom.xml
中添加以下依赖。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
- 对JWT进行配置
首先要定义一个类,用于封装加密JWT时需要的信息,包括JWT的发行人、主题等。如下:
@Component
@ConfigurationProperties(prefix = "jwt")
public class JwtConfig {
// key
private String key;
// 过期时间,单位:秒。默认2小时
private long expire = 7200;
// header字段
private String header = "Authorization";
// token 前缀
private String prefix = "Bearer ";
// 获取 JWT 签发者
private String issuer;
// 获取指定的声明
private Map<String, Object> claims = new HashMap<>();
// getter setter 设置默认值
}
主要考虑到了:
- key 就是 JWT 的密钥
- expire 是 JWT 的有效期,单位是 秒
- header 是将 JWT 存储在 HTTP 请求中时的 key
- prefix 是 JWT 存储时,前缀字符串
- issuer 表示 JWT 签发者
-
claims 表示 JWT 自身声明信息
-
在 Spring Security 配置类中添加 JWT
首先编写一个获取用户ID的方法public String getCurrentUserId() { ... }
,根据当前的 Authentication 对象获取当前用户 ID。
编写完毕后,我们就可以在 Spring Security 配置类中使用JWT了。如下:
@Configuration
@EnableWebSecurity
public class SecurityConfigurer extends WebSecurityConfigurerAdapter {
@Autowired
private JwtConfig jwtConfig;
@Autowired
private JwtUserDetailsService jwtUserDetailsService;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(jwtUserDetailsService)
.passwordEncoder(passwordEncoder());
}
@Bean
public AuthenticationTokenFilter authenticationTokenFilterBean() throws Exception {
return new AuthenticationTokenFilter(jwtConfig, jwtUserDetailsService);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
// 允许访问的接口
http.authorizeRequests()
.antMatchers(
"/swagger-ui.html",
"/swagger-resources/**",
"/v2/api-docs",
"/auth/**"
)
.permitAll();
http.authorizeRequests().anyRequest().authenticated();
// 定义登录页和默认跳转路径
http.formLogin().loginPage("/auth/login").defaultSuccessURL("/").permitAll();
// 定义登出操作
http.logout().logoutUrl("/auth/logout").permitAll()
.logoutSuccessUrl("/auth/login");
// 添加JWT过滤器
http.addFilterBefore(authenticationTokenFilterBean(),
UsernamePasswordAuthenticationFilter.class);
}
}
- 使用JWT进行用户认证
在登录接口中,用户需要提供用户名和密码,系统通过加密之后获得JWT的Token,然后返回给客户端。客户端访问服务器的其他接口时,将Token作为Authorization字段加入HTTP请求头中传递给服务器。
如果JWT验证成功,则说明用户已经登陆了,可以访问需要登陆才能访问的API了。例如:
@RestController
@RequestMapping("/api")
public class ApiController {
@GetMapping("/hello")
@PreAuthorize("hasRole('USER')")
public String hello() {
return "Hello, JWT!";
}
}
4. 示例说明
示例1:通过JWT认证需要用户登录后才能获取的资料
- 登录
POST:/auth/login
BODY:
{
"username": "test",
"password": "123456"
}
返回:
{
"code": 200,
"msg": "登录成功",
"data": {
"id": 1,
"username" : "test",
"token": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0ZXN0IiwiaWF0IjoxNTkyNTc0MzEyLCJleHAiOjE1OTI1OTExMTIsImF1ZCI6InBhc3N3b3JkIiwiaXNzIjoibmlnaHQiLCJuYmYiOjE1OTI1NzQzMTJ9.aFT_iSOLOZFTZiS5iOONCTwb5tU5-2bzcE1k8H5jvXw"
}
}
- 获取需要认证才能访问的资源
GET:/api/hello
Header:
Authorization:Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0ZXN0IiwiaWF0IjoxNTkyNTc0MzEyLCJleHAiOjE1OTI1OTEwOTIsImF1ZCI6InBhc3N3b3JkIiwiaXNzIjoibmlnaHQiLCJuYmYiOjE1OTI1NzQzMTJ9.aFT_iSOLOZFTZiS5iOONCTwb5tU5-2bzcE1k8H5jvXw
返回:
{
"code": 200,
"msg": "请求成功",
"data": "Hello, JWT!"
}
示例2:使用JWT实现文件上传接口的安全
- 登录
POST:/auth/login
BODY:
{
"username": "test",
"password": "123456"
}
返回:
{
"code": 200,
"msg": "登录成功",
"data": {
"id": 1,
"username": "test",
"token": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0ZXN0IiwiaWF0IjoxNTkyNTc0MzEyLCJleHAiOjE1OTI1OTEwOTIsImF1ZCI6InBhc3N3b3JkIiwiaXNzIjoibmlnaHQiLCJuYmYiOjE1OTI1NzQzMTJ9.aFT_iSOLOZFTZiS5iOONCTwb5tU5-2bzcE1k8H5jvXw"
}
}
- 上传文件
POST:/api/file/upload
Header:
Authorization:Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0ZXN0IiwiaWF0IjoxNTkyNTc0MzEyLCJleHAiOjE1OTI1OTEwOTIsImF1ZCI6InBhc3N3b3JkIiwiaXNzIjoibmlnaHQiLCJuYmYiOjE1OTI1NzQzMTJ9.aFT_iSOLOZFTZiS5iOONCTwb5tU5-2bzcE1k8H5jvXw
BODY:
{
"file": "Base64文件字符串"
}
返回:
{
"code": 200,
"msg": "请求成功",
"data": "文件上传成功"
}
以上就是使用SpringBoot、SpringSecurity和JWT实现系统安全策略的详细攻略,具体实现方法可以参考示例。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:SpringBoot SpringSecurity JWT实现系统安全策略详解 - Python技术站