我来详细讲解一下“Spring Security结合JWT的方法教程”的完整攻略。
1. 什么是Spring Security和JWT
Spring Security是一种基于框架的安全性解决方案,它为Java应用程序提供了身份验证和身份验证授权功能。
JWT(JSON Web Token)是一种身份验证和授权的标准,它将声明和签名打包在一个安全令牌中。JWT不需要在服务器上保存会话状态,它可以让你的服务器成为无状态的。
结合Spring Security和JWT可以构建一个安全而高效的后端系统,本文将介绍如何实现这一目标。
2. Spring Security结合JWT的实现步骤
2.1 添加Spring Security和JWT依赖
首先,需要将Spring Security和JWT依赖添加到项目中。在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.7.0</version>
</dependency>
2.2 实现用户认证
接下来,需要实现用户认证功能。具体来说,这个功能应该包括一个实现UserDetailsService
接口的类(用于从数据库或其他持久化存储中获取用户信息)和一个实现AuthenticationProvider
接口的类(用于验证用户提供的登录凭据)。在实现完这两个类之后,需要将它们添加到Spring的安全配置中。
示例代码:
MyUserDetailsService.java
@Service
public class MyUserDetailsService implements UserDetailsService {
private final UserService userService;
public MyUserDetailsService(UserService userService) {
this.userService = userService;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userService.getUserByUsername(username).orElseThrow(() -> new UsernameNotFoundException("User not found"));
return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), new ArrayList<>());
}
}
MyAuthenticationProvider.java
@Component
public class MyAuthenticationProvider implements AuthenticationProvider {
private final MyUserDetailsService userDetailsService;
private final PasswordEncoder passwordEncoder;
public MyAuthenticationProvider(MyUserDetailsService userDetailsService, PasswordEncoder passwordEncoder) {
this.userDetailsService = userDetailsService;
this.passwordEncoder = passwordEncoder;
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = authentication.getPrincipal().toString();
String password = authentication.getCredentials().toString();
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
if (!passwordEncoder.matches(password, userDetails.getPassword())) {
throw new BadCredentialsException("Invalid credentials");
}
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password, userDetails.getAuthorities());
token.setDetails(userDetails);
return token;
}
@Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}
在WebSecurityConfigurerAdapter
的子类中添加这两个类:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final MyUserDetailsService userDetailsService;
private final MyAuthenticationProvider authenticationProvider;
public SecurityConfig(MyUserDetailsService userDetailsService, MyAuthenticationProvider authenticationProvider) {
this.userDetailsService = userDetailsService;
this.authenticationProvider = authenticationProvider;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
auth.authenticationProvider(authenticationProvider);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// ...
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
2.3 实现JWT功能
接下来需要实现JWT功能。具体而言,需要实现一个能够生成JWT token的方法和一个能够验证token并从其中提取用户信息的方法。
示例代码:
JwtUtil.java
@Component
public class JwtUtil {
private static final String SECRET_KEY = "mySecretKey";
private static final int TOKEN_EXPIRATION = 1800;
public String generateToken(User user) {
Map<String, Object> claims = new HashMap<>();
claims.put("username", user.getUsername());
claims.put("roles", user.getRoles());
Date now = new Date();
Date expiration = new Date(now.getTime() + TOKEN_EXPIRATION * 1000L);
return Jwts.builder()
.setClaims(claims)
.setIssuedAt(now)
.setExpiration(expiration)
.signWith(SignatureAlgorithm.HS256, SECRET_KEY)
.compact();
}
public Optional<User> getUserFromToken(String token) {
try {
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token);
String username = claimsJws.getBody().get("username", String.class);
@SuppressWarnings("unchecked")
List<String> roles = claimsJws.getBody().get("roles", List.class);
User user = new User();
user.setUsername(username);
user.setRoles(roles);
return Optional.of(user);
} catch (JwtException e) {
return Optional.empty();
}
}
}
2.4 配置Spring Security以适应JWT
最后,只需要为Spring Security添加配置来包含JWT功能即可。
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final MyUserDetailsService userDetailsService;
private final MyAuthenticationProvider authenticationProvider;
private final JwtUtil jwtUtil;
public SecurityConfig(MyUserDetailsService userDetailsService, MyAuthenticationProvider authenticationProvider, JwtUtil jwtUtil) {
this.userDetailsService = userDetailsService;
this.authenticationProvider = authenticationProvider;
this.jwtUtil = jwtUtil;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
auth.authenticationProvider(authenticationProvider);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/api/authenticate").permitAll()
.anyRequest().authenticated()
.and()
.addFilterBefore(new JwtAuthenticationFilter(jwtUtil), UsernamePasswordAuthenticationFilter.class)
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
3. 示例
下面将简单介绍两个使用JWT的示例。
3.1 用户登录和获取用户信息
前端向后端发送请求,使用JWT进行用户登录验证,并获取当前用户信息。
authenticate
请求实现用户登录,user-data
请求获取用户信息。在响应中,后端将返回一个包含当前用户信息的JWT token,前端在使用user-data
请求时,带上此token,从而验证用户身份,并获取用户信息。
后端实现:
@RestController
@RequestMapping("/api")
public class UserController {
private final MyUserDetailsService userDetailsService;
private final JwtUtil jwtUtil;
public UserController(MyUserDetailsService userDetailsService, JwtUtil jwtUtil) {
this.userDetailsService = userDetailsService;
this.jwtUtil = jwtUtil;
}
@PostMapping("/authenticate")
public ResponseEntity<?> authenticate(@RequestBody LoginRequest loginRequest) {
try {
Authentication authentication = new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword());
authentication = new MyAuthenticationProvider(userDetailsService, passwordEncoder()).authenticate(authentication);
UserDetails userDetails = (UserDetails) authentication.getDetails();
String token = jwtUtil.generateToken(userService.getUserByUsername(loginRequest.getUsername()));
return ResponseEntity.ok(new JwtResponse(token));
} catch (BadCredentialsException e) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
}
}
@GetMapping("/user-data")
public ResponseEntity<?> getUserData(HttpServletRequest request) {
Optional<User> user = Optional.empty();
String authHeader = request.getHeader("Authorization");
if (authHeader != null && authHeader.startsWith("Bearer ")) {
String token = authHeader.substring(7);
user = jwtUtil.getUserFromToken(token);
}
return user.map(ResponseEntity::ok).orElse(ResponseEntity.status(HttpStatus.UNAUTHORIZED).build());
}
}
前端实现:
const login = (username, password) => {
return axios.post('/api/authenticate', {
username, password
}).then(response => {
const token = response.data.token;
localStorage.setItem('token', token);
axios.defaults.headers.common['Authorization'] = `Bearer ${token}`;
}).catch(error => {
console.log(error);
});
};
const getUserData = () => {
return axios.get('/api/user-data').then(response => {
return response.data;
}).catch(error => {
console.log(error);
});
};
3.2 通过JWT进行API调用的身份验证
前端使用JWT token以请求头的形式向后端API发起请求。
后端实现:
@RestController
@RequestMapping("/api")
public class MyController {
@GetMapping("/test")
public ResponseEntity<?> test(@RequestHeader("Authorization") String authHeader) {
if (authHeader != null && authHeader.startsWith("Bearer ")) {
String token = authHeader.substring(7);
Optional<User> user = jwtUtil.getUserFromToken(token);
// do something with user
return ResponseEntity.ok().build();
}
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
}
}
前端实现:
const testApi = () => {
const token = localStorage.getItem('token');
return axios.get('/api/test', {
headers: {
Authorization: `Bearer ${token}`
}
}).then(response => {
return response.data;
}).catch(error => {
console.log(error);
});
};
好了,以上就是关于Spring Security结合JWT的方法教程的完整攻略。希望对你有所帮助。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Spring Security结合JWT的方法教程 - Python技术站