日期:2023-04-07 07:05:33 来源:腾讯云
JWT(JSON Web Token)是一种用于在网络中传输安全信息的开放标准(RFC 7519)。它可以在各个服务之间安全地传递用户认证信息,因为它使用数字签名来验证信息的真实性和完整性。
JWT有三个部分,每个部分用点(.)分隔:
Header:通常包含JWT使用的签名算法和令牌类型。Payload:包含有关用户或其他主题的声明信息。声明是有关实体(通常是用户)和其他数据的JSON对象。声明被编码为JSON,然后使用Base64 URL编码。Signature:用于验证消息是否未被篡改并且来自预期的发送者。签名由使用Header中指定的算法和秘钥对Header和Payload进行加密产生。在Spring Boot中,您可以使用Spring Security和jjwt库来实现JWT的认证和授权。下面是一个使用JWT的示例:
(资料图片仅供参考)
@Configuration@EnableWebSecuritypublic class SecurityConfig extends WebSecurityConfigurerAdapter { @Value("${jwt.secret}") private String jwtSecret; @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeRequests() .antMatchers(HttpMethod.POST, "/api/authenticate").permitAll() .anyRequest().authenticated() .and() .addFilter(new JwtAuthenticationFilter(authenticationManager(), jwtSecret)) .addFilter(new JwtAuthorizationFilter(authenticationManager(), jwtSecret)) .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); } @Override public void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(new JwtAuthenticationProvider(jwtSecret)); }}在上面的示例中,SecurityConfig类继承了WebSecurityConfigurerAdapter并使用了@EnableWebSecurity注解启用Spring Security。configure()方法使用HttpSecurity对象来配置HTTP请求的安全性。.csrf().disable()禁用了CSRF保护。.authorizeRequests()表示进行授权请求。.antMatchers(HttpMethod.POST, "/api/authenticate").permitAll()表示允许POST请求到/api/authenticate路径。.anyRequest().authenticated()表示要求所有其他请求都需要身份验证。.addFilter(new JwtAuthenticationFilter(authenticationManager(), jwtSecret))和.addFilter(new JwtAuthorizationFilter(authenticationManager(), jwtSecret))分别添加JWT认证和授权过滤器。.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)指定了会话管理策略。
configure()方法中还有一个configure(AuthenticationManagerBuilder auth)方法,它使用JwtAuthenticationProvider类配置身份验证。在这里,jwtSecret被注入到JwtAuthenticationProvider构造函数中,以便在认证过程中使用。
下面是JwtAuthenticationFilter和JwtAuthorizationFilter的实现:
public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter { private final AuthenticationManager authenticationManager; private final String jwtSecret; public JwtAuthenticationFilter(AuthenticationManager authenticationManager, String jwtSecret) { this.authenticationManager = authenticationManager; this.jwtSecret = jwtSecret; setFilterProcessesUrl("/api/authenticate"); } @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) { try { LoginRequest loginRequest = new ObjectMapper().readValue(request.getInputStream(), LoginRequest.class); Authentication authentication = new UsernamePasswordAuthenticationToken( loginRequest.getUsername(), loginRequest.getPassword() ); return authenticationManager.authenticate(authentication); } catch (IOException e) { throw new RuntimeException(e); } } @Override protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) { UserPrincipal userPrincipal = (UserPrincipal) authResult.getPrincipal(); String token = Jwts.builder() .setSubject(userPrincipal.getUsername()) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() + 864000000)) .signWith(SignatureAlgorithm.HS512, jwtSecret) .compact(); response.addHeader("Authorization", "Bearer " + token); }}JwtAuthenticationFilter类继承了UsernamePasswordAuthenticationFilter类,它用于处理基于用户名和密码的身份验证。它还使用AuthenticationManager来验证用户名和密码是否正确。jwtSecret在构造函数中被注入,用于生成JWT令牌。
在attemptAuthentication()方法中,LoginRequest对象被反序列化为从请求中获取的用户名和密码。这些值被封装到UsernamePasswordAuthenticationToken中,并传递给AuthenticationManager以验证用户身份。
在身份验证成功后,successfulAuthentication()方法被调用。在这里,UserPrincipal对象被从Authentication对象中获取,然后使用Jwts类生成JWT令牌。setSubject()方法将用户名设置为JWT主题。setIssuedAt()方法设置JWT令牌的发行时间。setExpiration()方法设置JWT令牌的到期时间。signWith()方法使用HS512算法和jwtSecret密钥对JWT令牌进行签名。最后,JWT令牌被添加到响应标头中。
下面是JwtAuthorizationFilter的实现:
public class JwtAuthorizationFilter extends BasicAuthenticationFilter { private final String jwtSecret; public JwtAuthorizationFilter(AuthenticationManager authenticationManager, String jwtSecret) { super(authenticationManager); this.jwtSecret = jwtSecret; } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { String authorizationHeader = request.getHeader("Authorization"); if (authorizationHeader == null || !authorizationHeader.startsWith("Bearer ")) { chain.doFilter(request, response); return; } String token = authorizationHeader.replace("Bearer ", ""); try { Jws claimsJws = Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token); String username = claimsJws.getBody().getSubject(); List authorities = (List) claimsJws.getBody().get("authorities"); List grantedAuthorities = authorities.stream() .map(SimpleGrantedAuthority::new) .collect(Collectors.toList()); Authentication authentication = new UsernamePasswordAuthenticationToken(username, null, grantedAuthorities); SecurityContextHolder.getContext().setAuthentication(authentication); chain.doFilter(request, response); } catch (JwtException e) { response.setStatus(HttpStatus.UNAUTHORIZED.value()); } }} JwtAuthorizationFilter类继承了BasicAuthenticationFilter类,并覆盖了doFilterInternal()方法。在这个方法中,请求头中的Authorization标头被解析,如果它不是以Bearer开头,则直接传递给过滤器链。否则,从令牌中解析出主题(用户名)和授权信息,然后创建一个包含用户身份验证和授权信息的Authentication对象,并将其设置到SecurityContextHolder中。
如果JWT令牌无效,JwtException将被抛出,并返回HTTP 401未经授权的错误。
标签:
Spring Boot的安全配置(三) 焦点资讯
选择大城市逐梦还是小城市安稳:即时
ipad2018(ipad用处) 全球独家
天天热议:6月20日是什么星座的_6月20日是什么星座
智齿拔了有什么影响吗什么时候拔最好_智齿拔了有什么影响
2023胡润全球白手起家U40富豪榜出炉,张一鸣位居第二 全球头条
利润持续走低,传统加油站如何走出新的“增长曲线”?
完成4颗卫星发射任务 河南卫星及应用产业发展工作方案出炉
如何挑选营养性化妆品 挑选营养性化妆品的技巧-时讯
世界热文:干墨鱼怎么做好吃 家常做法_墨鱼的做法
Redmi Note 12S来了:2200元 开机就是MIUI 14
和讯个股快报:2023年04月06日 光环新网(300383)该股换手率大于8%
今日精选:3月全球制造业PMI降至49.1% 全球经济复苏动能依然不足
眼影 微资讯
环球热推荐:重庆姐弟坠亡案二审今日开庭
孝昌:“四好农村路”绘就乡村“幸福路”_环球热推荐
《了不起的夜晚》惊喜专场口碑 邵艺辉林允马旭东称赞类型片尝试_环球快消息
组件与硅料价格走势背离 产业链利润如何再分配?_世界简讯
世界新消息丨为什么毛衣和长裙才是春日官配?
英雄之光丨写给因公牺牲警察丈夫的一封信:身为警嫂,我决不拖你后腿
国内头部数字人齐聚,数字文化应用产品发布厅将亮相青岛数文会
清明寄哀思:缅怀角膜捐献者_环球热门
2019电费年度账单怎么查看 电费全年账单查询
英雄之光丨致敬“独胆英雄” 传承青春力量
清明节:我记得,你就不曾离开_世界报道