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未经授权的错误。
智通财经获悉,浙商证券发布研究报告称,半导体设备是整个半导体产业链的基石,当下时点库存周期拐点将...
01:331万公里外,蔡英文刚刚结束对中美洲两国的 "窜访 ",又再次 "过境 "美国。从纽约到洛杉矶,迎...
2023年4月,A股有153家公司的限售股面临解禁,合计解禁量约为116 88亿股,解禁市值超2400亿元。其中,...
1、凊qìng凉。2、清凉。3、寒冷。4、樫jiān一种鸟,形似乌鸦。5、騨 驒(騨的单上多一点,驒是个日本汉
1、 美食,顾名思义就是美味的食物,贵的有山珍海味,便宜的有街边小吃。下面跟着小编来看看西单美食...
76人今日103-101力克凯尔特人,赛后,本场砍下52分的76人球星恩比德接受了媒体采访。“从一开场,我就想...
4月5日,应莹在微博发文称,昨天,我收到了上海黄浦区人民法院的离婚案判决书。从2019年3月底递交起诉状...
属狗的适合的礼物,我想爸都会用到,可以买一个爸爸喜欢的东西。爸爸是属蛇的,平时工作很辛苦,也很累...
首个获得奥斯卡奖的中国女导演赵婷(ChloéZhao)继牛仔、美国流浪者、超能力神族、西部吸血鬼之后,又...
核废水中的放射性物质在被释放到人类所依赖的海洋水域后,可能会对人类健康造成不良的影响。总之,世界...
1、纠正一下:不要乱用眼药水~!眼睛痒可能是结膜炎,最好去医院确诊一下。2、结膜炎的话,用曼秀雷敦,...
相约安徽·向春而行|一口清明粿,赴春天之约
每日甘肃网讯(新甘肃·每日甘肃网记者王宇晨)记者从甘肃省商务厅获悉,3月26日至3月31日,由省商务厅...
东方电热:预计一季度净利润同比增长0 42%-29 85%:东方电热(300217)公告,预计一季度净利润5800万...
安东·拉索认为,俄乌冲突持续,让整个欧洲都受到了深远的影响。而眼下,西方国家还在不断加码向乌克兰...
紫鑫药业(002118)04月04日在投资者关系平台上答复了投资者关心的问题。
1、我做过一没腊肉来卖,不过是正宗土猪,光买肉是十三块一斤。2、买的后腿肉,因为瘦肉多点,二个后腿...
证券时报e公司讯,海普瑞(002399)4月3日晚间公告,全资子公司TechdowUSAInc (简称天道美国)于3月30日与...
中新网4月4日电(中新财经记者左宇坤)二手房交易流程与成本,迎来重大变动。在传统的交易观念里,“一手...
中储发展股份有限公司副总裁王勇认为,3月,仓储指数有明显回落,主要是受前期基数较高影响,但指数...
【智车派新闻】4月3日,奔驰官方在推特放出了一张奔驰GLS改款车型的预热图,奔驰方面称,新车将会在当地...
证券时报网讯,据新华社消息,日本央行3日公布的企业短期经济观测调查(日银短观)结果显示,今年第一季度...
新邵县陈家坊镇富阳村大喇叭广播扰民投诉直通车是湖南日报、华声在线、新湖南主办的投诉维权类栏目,帮助...
今日,NBA常规赛篮网111-110击败爵士。赛后,篮网球员布里奇斯接受了记者采访。布里奇斯在采访中谈到了...
1、俄罗斯是一个欧洲国家。欧洲,全称“欧洲”(Europe),其名称来源于希腊神话人物“欧罗巴”,位于东半...