spring security+jwt单点登录
时间: 2023-07-28 21:08:55 浏览: 102
Spring Security是一个基于Spring框架的安全框架,它提供了一系列的安全服务,包括认证、授权、攻击防护等。而JWT(JSON Web Token)是一种轻量级的身份认证和授权机制,它可以在不同的系统之间安全地传递信息。Spring Security和JWT可以结合使用,实现更加安全的身份认证和授权机制。通过使用JWT,可以避免在服务器端存储用户的身份信息,从而提高系统的安全性。
相关问题
springsecurity+jwt单点登录原理
Spring Security和JWT(JSON Web Token)是两个不同的概念和技术,但可以结合使用来实现单点登录。
Spring Security是一个强大的身份验证和访问控制框架,用于保护应用程序的安全性。它提供了一组功能丰富的工具和库,用于处理认证、授权和安全配置等方面的任务。
JWT是一种用于在网络应用中传递信息的开放标准(RFC 7519)。它由三部分组成:头部、载荷和签名。头部包含有关生成和验证JWT的元数据,载荷包含有关用户或其他实体的信息,签名用于验证JWT的完整性。
单点登录(SSO)是一种身份验证机制,允许用户使用一组凭据(例如用户名和密码)登录到一个系统后,即可无需再次输入凭据即可访问其他系统。
要实现基于Spring Security和JWT的单点登录,可以遵循以下步骤:
1. 用户成功登录到主系统(例如系统A),该系统生成并返回一个JWT给用户。
2. 用户尝试访问其他受保护的系统(例如系统B)时,在请求中包含JWT。
3. 系统B接收到请求后,使用公钥验证JWT的签名,并解析出用户信息。
4. 如果JWT验证成功且用户有权限访问系统B,则允许用户访问系统B。
需要注意的是,要实现真正的单点登录,还需要一个中心化的身份验证系统(例如OAuth2认证服务器),用于生成和验证JWT,并为不同的系统颁发相同的JWT。
此外,还可以使用Spring Security提供的一些配置来简化JWT的集成,例如自定义认证过滤器、授权管理器和认证提供者等。
总结起来,Spring Security和JWT可以结合使用来实现单点登录。Spring Security负责处理认证和授权,JWT用于传递用户信息和验证用户身份。
springsecurity+jwt实现单点登录代码流程
Spring Security结合JWT实现单点登录的代码流程如下:
1. 创建一个Spring Boot项目并添加以下依赖:
```
<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>
```
2. 在Spring Security配置类中添加以下代码:
```
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private JwtAuthenticationEntryPoint unauthorizedHandler;
@Autowired
private CustomUserDetailsService customUserDetailsService;
@Value("${jwt.secret}")
private String secret;
@Value("${jwt.expiration}")
private int expiration;
@Bean
public JwtAuthenticationFilter authenticationTokenFilter() {
return new JwtAuthenticationFilter();
}
@Override
public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder
.userDetailsService(customUserDetailsService)
.passwordEncoder(passwordEncoder());
}
@Bean(BeanIds.AUTHENTICATION_MANAGER)
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors()
.and()
.csrf()
.disable()
.exceptionHandling()
.authenticationEntryPoint(unauthorizedHandler)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/api/auth/**")
.permitAll()
.anyRequest()
.authenticated();
// 添加JWT过滤器
http.addFilterBefore(authenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);
}
@Bean
public JwtTokenProvider jwtTokenProvider() {
return new JwtTokenProvider(secret, expiration);
}
}
```
3. 创建一个JwtTokenProvider类,实现JWT的生成、解析和验证:
```
@Service
public class JwtTokenProvider {
private final String secret;
private final long expiration;
@Autowired
public JwtTokenProvider(@Value("${jwt.secret}") String secret, @Value("${jwt.expiration}") long expiration) {
this.secret = secret;
this.expiration = expiration;
}
public String generateToken(Authentication authentication) {
UserPrincipal userPrincipal = (UserPrincipal) authentication.getPrincipal();
Date now = new Date();
Date expiryDate = new Date(now.getTime() + expiration);
return Jwts.builder()
.setSubject(Long.toString(userPrincipal.getId()))
.setIssuedAt(new Date())
.setExpiration(expiryDate)
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
}
public Long getUserIdFromToken(String token) {
Claims claims = Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
return Long.parseLong(claims.getSubject());
}
public boolean validateToken(String token) {
try {
Jwts.parser().setSigningKey(secret).parseClaimsJws(token);
return true;
} catch (SignatureException ex) {
System.out.println("Invalid JWT signature");
} catch (MalformedJwtException ex) {
System.out.println("Invalid JWT token");
} catch (ExpiredJwtException ex) {
System.out.println("Expired JWT token");
} catch (UnsupportedJwtException ex) {
System.out.println("Unsupported JWT token");
} catch (IllegalArgumentException ex) {
System.out.println("JWT claims string is empty.");
}
return false;
}
}
```
4. 创建一个JwtAuthenticationFilter类,拦截请求并验证JWT:
```
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Autowired
private JwtTokenProvider jwtTokenProvider;
@Autowired
private CustomUserDetailsService customUserDetailsService;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
try {
String jwt = getJwtFromRequest(request);
if (StringUtils.hasText(jwt) && jwtTokenProvider.validateToken(jwt)) {
Long userId = jwtTokenProvider.getUserIdFromToken(jwt);
UserDetails userDetails = customUserDetailsService.loadUserById(userId);
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
} catch (Exception ex) {
logger.error("Could not set user authentication in security context", ex);
}
filterChain.doFilter(request, response);
}
private String getJwtFromRequest(HttpServletRequest request) {
String bearerToken = request.getHeader("Authorization");
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
return bearerToken.substring(7, bearerToken.length());
}
return null;
}
}
```
5. 创建一个JwtAuthenticationEntryPoint类,处理未授权的请求:
```
@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
}
}
```
6. 创建一个UserPrincipal类,实现Spring Security的UserDetails接口:
```
public class UserPrincipal implements UserDetails {
private Long id;
private String username;
private String email;
private String password;
private Collection<? extends GrantedAuthority> authorities;
public UserPrincipal(Long id, String username, String email, String password, Collection<? extends GrantedAuthority> authorities) {
this.id = id;
this.username = username;
this.email = email;
this.password = password;
this.authorities = authorities;
}
public Long getId() {
return id;
}
public String getEmail() {
return email;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return username;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
```
7. 创建一个CustomUserDetailsService类,实现Spring Security的UserDetailsService接口:
```
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Override
@Transactional
public UserDetails loadUserByUsername(String usernameOrEmail) throws UsernameNotFoundException {
User user = userRepository.findByUsernameOrEmail(usernameOrEmail, usernameOrEmail)
.orElseThrow(() ->
new UsernameNotFoundException("User not found with username or email : " + usernameOrEmail)
);
return UserPrincipal.create(user);
}
@Transactional
public UserDetails loadUserById(Long id) {
User user = userRepository.findById(id)
.orElseThrow(() ->
new ResourceNotFoundException("User", "id", id)
);
return UserPrincipal.create(user);
}
}
```
以上就是Spring Security结合JWT实现单点登录的代码流程,可以根据具体的需求进行相应的修改和调整。
阅读全文