下面是“SpringBoot+SpringSecurity+JWT实现系统认证与授权”的完整攻略:
一、什么是Spring Boot、Spring Security和JWT
- Spring Boot:是一个快速开发框架,能够简化Spring应用程序的创建和开发过程。
- Spring Security:是Spring框架中提供的一套安全服务框架,可以用来保护Web应用程序,场景包括认证(authentication)、授权(authorization)和密码学(cryptography)等。
- JWT(JSON Web Token):是一种基于JSON的轻量级授权和身份验证协议,主要用于Web应用程序和API的安全传输。
二、如何使用Spring Boot、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.9.0</version>
</dependency>
- 配置Spring Security和JWT相关属性
在application.yml文件中添加以下配置:
#JWT配置
jwt:
header:
name: Authorization
prefix: Bearer
secret: JWTSecretKey
expiration: 604800000 #7天过期时间,单位毫秒
# 关闭csrf验证,jwt不需要csrf
security:
csrf:
enabled: false
- 实现Spring Security的认证和授权逻辑
自定义一个继承了WebSecurityConfigurerAdapter类的WebSecurityConfig类,重写configure方法来实现相应的认证和授权逻辑。
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
//在这里重写configure方法来实现相应的认证和授权逻辑
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.csrf().disable()
.authorizeRequests()
.antMatchers("/api/authenticate").permitAll()
.anyRequest().authenticated()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
httpSecurity.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
}
@Bean
public JwtAuthFilter authenticationJwtTokenFilter() {
return new JwtAuthFilter();
}
}
- 实现JWT的Token生成和解析逻辑
自定义一个JwtUtils类,实现JWT的Token生成和解析逻辑。
@Component
public class JwtUtils {
private String jwtSecret = "JWTSecretKey";
private int jwtExpirationMs = 604800000; //7天过期时间,单位毫秒
public String generateJwtToken(Authentication authentication) {
UserDetailsImpl userPrincipal = (UserDetailsImpl) authentication.getPrincipal();
return Jwts.builder()
.setSubject((userPrincipal.getUsername()))
.setIssuedAt(new Date())
.setExpiration(new Date((new Date()).getTime() + jwtExpirationMs))
.signWith(SignatureAlgorithm.HS512, jwtSecret)
.compact();
}
public String getUsernameFromJwtToken(String token) {
return Jwts.parser()
.setSigningKey(jwtSecret)
.parseClaimsJws(token)
.getBody().getSubject();
}
}
- 实现JWT的认证过滤器逻辑
自定义一个JwtAuthFilter类,实现JWT的认证过滤器逻辑。
public class JwtAuthFilter extends OncePerRequestFilter {
@Autowired
private JwtUtils jwtUtils;
@Autowired
private UserDetailsServiceImpl userDetailsService;
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain)
throws ServletException, IOException {
try {
String jwt = parseJwt(request);
if (jwt != null && jwtUtils.validateJwtToken(jwt)) {
String username = jwtUtils.getUsernameFromJwtToken(jwt);
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
} catch (Exception e) {
logger.error("Cannot set user authentication: {}", e);
}
filterChain.doFilter(request, response);
}
private String parseJwt(HttpServletRequest request) {
String headerAuth = request.getHeader("Authorization");
if (StringUtils.hasText(headerAuth) && headerAuth.startsWith("Bearer ")) {
return headerAuth.substring(7, headerAuth.length());
}
return null;
}
}
- 实现UserDetails的逻辑
自定义一个实现UserDetails接口的UserDetailsImpl类。
public class UserDetailsImpl implements UserDetails {
private Integer id;
private String username;
private String password;
private Collection<? extends GrantedAuthority> authorities;
public UserDetailsImpl(Integer id, String username, String password,
Collection<? extends GrantedAuthority> authorities) {
this.id = id;
this.username = username;
this.password = password;
this.authorities = authorities;
}
public static UserDetailsImpl build(User user) {
List<GrantedAuthority> authorities = user.getRoles().stream()
.map(role -> new SimpleGrantedAuthority(role.getName().name()))
.collect(Collectors.toList());
return new UserDetailsImpl(
user.getId(),
user.getUsername(),
user.getPassword(),
authorities);
}
//省略getter和setter方法以及其他接口方法的实现
}
- 实现UserDetailsService的逻辑
自定义一个实现UserDetailsService接口的UserDetailsServiceImpl类。
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
UserRepository userRepository;
@Override
@Transactional
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("User Not Found with username: " + username));
return UserDetailsImpl.build(user);
}
}
至此,我们完成了使用Spring Boot、Spring Security和JWT来实现系统认证与授权的全部步骤。
三、示例
下面是两个示例,演示如何使用Spring Boot、Spring Security和JWT来实现系统认证与授权。
示例一:用户认证
实现基于SpringBoot、SpringSecurity和JWT的用户认证演示程序,可参考以下代码:
@RestController
@RequestMapping("/api")
public class AuthController {
@Autowired
AuthenticationManager authenticationManager;
@Autowired
JwtUtils jwtUtils;
@PostMapping("/authenticate")
public ResponseEntity<?> authenticateUser(@Valid @RequestBody LoginRequest loginRequest) {
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword()));
SecurityContextHolder.getContext().setAuthentication(authentication);
String jwt = jwtUtils.generateJwtToken(authentication);
return ResponseEntity.ok(new JwtResponse(jwt));
}
}
示例二:资源授权
实现基于SpringBoot、SpringSecurity和JWT的资源授权演示程序,可参考以下代码:
@RestController
@RequestMapping("/api")
public class UserController {
@Autowired
UserRepository userRepository;
@GetMapping("/users/{id}")
@PreAuthorize("hasRole('USER') or hasRole('ADMIN')")
public ResponseEntity<User> getUserById(@PathVariable(value = "id") Integer userId) {
User user = userRepository.findById(userId).orElseThrow(() -> new ResourceNotFoundException("User", "id", userId));
return ResponseEntity.ok().body(user);
}
}
在这个示例中,我们使用了@PreAuthorize注解,它表示只有在用户有“USER”或“ADMIN”角色时才能访问该接口。
以上是关于“SpringBoot+SpringSecurity+JWT实现系统认证与授权示例”的完整攻略。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:SpringBoot+SpringSecurity+JWT实现系统认证与授权示例 - Python技术站