下面我将详细讲解一下“Spring Security基于Token的认证方式”的完整攻略。
什么是Token认证方式
Token认证方式,是一种基于令牌(Token)的身份认证方式。在客户端成功登录后,服务端会生成一个Token,这个Token会放到HTTP响应头中或者响应体中返回给客户端,客户端需要在后续的请求中携带该Token才能访问资源。
Token认证的优点
- 无状态性:在服务端不需要记录用户的状态,避免了Session数据空间的浪费。
- 有效期管理:能够简单高效地在服务端对Token的有效期进行管理,从而减少了服务端的资源消耗。
- 部署部署:能够方便、快捷地进行服务端间的数据传输,例如:在分布式系统中。
实现Token认证的步骤
- 实现用户登录
- 接收登录成功后返回的Token并存储
- 根据Token判断用户是否已经登录
- 实现Token过期时间
- 实现Token注销
实现方式
1.使用Spring Security实现Token认证
在Spring Security中,可以使用UsernamePasswordAuthenticationFilter
来拦截登录请求,生成Token并返回给客户端。而在后续请求中,可以使用BearerTokenAuthenticationFilter
来对Token进行认证。
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
@Bean
public JwtAuthenticationFilter jwtAuthenticationFilter() {
return new JwtAuthenticationFilter();
}
@Override
public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder
.userDetailsService(userDetailsService)
.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
.csrf().disable()
.exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
.antMatchers("/api/auth/**").permitAll()
.antMatchers("/api/user/checkUsernameAvailability", "/api/user/checkEmailAvailability").permitAll()
.antMatchers(HttpMethod.GET, "/api/polls/**").permitAll()
.anyRequest().authenticated();
// Add custom JWT security filter
http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}
}
上面的代码中,我们通过@Bean
注解来创建JwtAuthenticationFilter和PasswordEncoder的Bean。在configure(AuthenticationManagerBuilder)
方法中设置了我们自定义的UserDetailsService,并使用BCryptPasswordEncoder加密密码。在AuthenticationManager
的Bean中使用@Bean(BeanIds.AUTHENTICATION_MANAGER)
来覆盖默认的org.springframework.security.authentication.AuthenticationManager
2.使用Spring框架手动实现Token认证
下面是一个手动实现Token认证的示例。其中,我们使用了OncePerRequestFilter
来对请求进行过滤,从而在请求被处理前进行认证操作。
@Component
public class JwtRequestFilter extends OncePerRequestFilter {
private static final Logger logger = LoggerFactory.getLogger(JwtRequestFilter.class);
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
final String requestTokenHeader = request.getHeader("Authorization");
String username = null;
String jwtToken = null;
// 去掉Bearer
if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) {
jwtToken = requestTokenHeader.substring(7);
try {
username = jwtTokenUtil.getUsernameFromToken(jwtToken);
} catch (IllegalArgumentException e) {
logger.error("Unable to get JWT Token");
} catch (ExpiredJwtException e) {
logger.error("JWT Token has expired");
}
} else {
logger.warn("JWT Token does not begin with Bearer String");
}
// 验证Token是否有效
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
if (jwtTokenUtil.validateToken(jwtToken, userDetails)) {
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
usernamePasswordAuthenticationToken
.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
}
}
chain.doFilter(request, response);
}
}
在上面的代码中,通过JwtTokenUtil对Token进行操作,如果Token有效,则对请求进行认证。
总结
总的来说,基于Token的认证是一种非常灵活、安全、高效的认证方式,使用Spring Security进行实现非常简单。如果需要手动实现,也不是很困难,需要在Filter中对请求进行拦截和校验即可。需要注意的是,Token的有效期一定要管理好,避免出现安全风险。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:springsecurity基于token的认证方式 - Python技术站