我叫果冻 2023-05-11 17:15 采纳率: 56.5%
浏览 15
已结题

token被截获,如何防止

问题 :用security+jwt 方案进行登录认证。那么登录成功后,生成的token如何防止被窃取

  • 写回答

1条回答 默认 最新

  • CSDN-Ada助手 CSDN-AI 官方账号 2023-05-11 21:18
    关注
    • 帮你找了个相似的问题, 你可以看下: https://ask.csdn.net/questions/7689696
    • 这篇博客你也可以参考下:第七章:使用jwt token的方式来进行登录
    • 除此之外, 这篇博客: Security之整合JWT篇中的 4、第一阶段,登录认证,获取token 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:
    • 首次登录,还是以传统的表单登录模式,所以我们可以直接使用UsernamePasswordAuthenticationFilter来拦截/login进行认证处理,不过我这里自定义了一个JwtAuthenticationFilter,其功能跟UsernamePasswordAuthenticationFilter差不多
      JwtAuthenticationFilter 继承 UsernamePasswordAuthenticationFilter 并重写 attemptAuthentication

      package com.yzm.security08.config;
      
      import org.apache.commons.lang3.StringUtils;
      import org.springframework.security.authentication.AuthenticationManager;
      import org.springframework.security.authentication.AuthenticationServiceException;
      import org.springframework.security.core.Authentication;
      import org.springframework.security.core.AuthenticationException;
      import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
      
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      
      public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
      
          public JwtAuthenticationFilter() {
              super();
          }
      
          public JwtAuthenticationFilter(AuthenticationManager authenticationManager) {
              super(authenticationManager);
          }
      
          public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
              String username = obtainUsername(request);
              String password = obtainPassword(request);
              if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) {
                  throw new AuthenticationServiceException("用户名密码错误");
              }
      		// 构造未鉴权的JwtAuthenticationToken 对象
              JwtAuthenticationToken authToken = new JwtAuthenticationToken(username, password);
              this.setDetails(request, authToken);
              return this.getAuthenticationManager().authenticate(authToken);
          }
      
      }
      

      JwtAuthenticationToken 继承 UsernamePasswordAuthenticationToken

      package com.yzm.security08.config;
      
      import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
      import org.springframework.security.core.GrantedAuthority;
      
      import java.util.Collection;
      
      public class JwtAuthenticationToken extends UsernamePasswordAuthenticationToken {
      
          public JwtAuthenticationToken(Object principal, Object credentials) {
              super(principal, credentials);
          }
      
          public JwtAuthenticationToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
              super(principal, credentials, authorities);
          }
      }
      

      身份认证 Provider,获取UserDetails对象,校验密码,构造鉴权的Authentication对象

      package com.yzm.security08.config;
      
      import lombok.extern.slf4j.Slf4j;
      import org.springframework.security.authentication.AuthenticationProvider;
      import org.springframework.security.authentication.BadCredentialsException;
      import org.springframework.security.core.Authentication;
      import org.springframework.security.core.AuthenticationException;
      import org.springframework.security.core.userdetails.UserDetails;
      import org.springframework.security.core.userdetails.UserDetailsService;
      import org.springframework.security.core.userdetails.UsernameNotFoundException;
      import org.springframework.security.crypto.password.PasswordEncoder;
      
      @Slf4j
      public class JwtAuthenticationProvider implements AuthenticationProvider {
      
          private final UserDetailsService userDetailsService;
          private final PasswordEncoder passwordEncoder;
      
          public JwtAuthenticationProvider(UserDetailsService userDetailsService, PasswordEncoder passwordEncoder) {
              this.userDetailsService = userDetailsService;
              this.passwordEncoder = passwordEncoder;
          }
      
          @Override
          public boolean supports(Class<?> authentication) {
              return JwtAuthenticationToken.class.isAssignableFrom(authentication);
          }
      
          @Override
          public Authentication authenticate(Authentication authentication) throws AuthenticationException {
              JwtAuthenticationToken authenticationToken = (JwtAuthenticationToken) authentication;
              String username = (String) authenticationToken.getPrincipal();
              String password = (String) authenticationToken.getCredentials();
      
              UserDetails userDetails = userDetailsService.loadUserByUsername(username);
              if (userDetails == null) throw new UsernameNotFoundException("账号异常");
      
              if (!passwordEncoder.matches(password, userDetails.getPassword())) {
                  throw new BadCredentialsException("凭证异常");
              }
      
              // 构造鉴权的JwtAuthenticationToken对象
              JwtAuthenticationToken resultToken = new JwtAuthenticationToken(username, password,
                      userDetails.getAuthorities());
              resultToken.setDetails(authentication.getDetails());
              return resultToken;
          }
      }
      

      登录认证成功之后,返回token

      package com.yzm.security08.config;
      
      import com.yzm.common.utils.HttpUtils;
      import com.yzm.security08.utils.JwtUtils;
      import lombok.extern.slf4j.Slf4j;
      import org.springframework.security.core.Authentication;
      import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
      
      import javax.servlet.ServletException;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      import java.io.IOException;
      import java.util.HashMap;
      import java.util.Map;
      
      @Slf4j
      public class JwtAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
      
          @Override
          public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws ServletException, IOException {
              if (authentication instanceof JwtAuthenticationToken) {
                  log.info("登录认证");
                  JwtAuthenticationToken authenticationToken = (JwtAuthenticationToken) authentication;
                  String username = (String) authenticationToken.getPrincipal();
      
                  Map<String, Object> map = new HashMap<>();
                  map.put(JwtUtils.USERNAME, username);
                  String token = JwtUtils.generateToken(map);
                  HttpUtils.successWrite(response, token);
              }
          }
      }
      
    • 您还可以看一下 崔海焘老师的新版前后端接口安全技术JWT+RSA加密课程中的 保证token一直有效-刷新token小节, 巩固相关知识点
    • 以下回答由chatgpt基于相关博客总结生成:

      为了防止他人截获或盗用登录令牌(token),可以采取以下措施:

      1. 使用https协议传输数据,以确保通信过程中的加密安全性。

      2. 设置token过期时间,限制token的有效时间。

      3. 采用密钥对token进行签名,防止他人伪造。密钥只在服务器端存储,不要泄漏。

      4. 不在代码中明文显示密钥,可以采用将密钥写在配置文件中,然后读取配置文件获取密钥。

      5. 不能将token存储在客户端的cookie和localStorage中,避免被恶意攻击者获取。

      6. 需要对请求头进行验证,只有携带正确的token且未过期才能进行相关操作。

      可以参考下面的代码:

      // 配置JWT生成工具类
      public class JwtTokenUtils {
      
          // 签名密钥,应与服务器端的密钥相同,保持安全
          private static final String secret = "yourSecretKey";
      
          // 过期时间,这里设置为2小时
          private static final long expireTime = 2 * 60 * 60 * 1000;
      
          /**
           * 生成token
           */
          public static String generateToken(String username, List<String> roles) {
              Date now = new Date();
              Date expireDate = new Date(now.getTime() + expireTime);
              Map<String, Object> claims = new HashMap<>();
              claims.put("username", username);
              claims.put("roles", roles);
              return Jwts.builder()
                      .setClaims(claims)
                      .setIssuedAt(now)
                      .setExpiration(expireDate)
                      .signWith(SignatureAlgorithm.HS256, secret)
                      .compact();
          }
      
          /**
           * 验证token是否有效
           */
          public static boolean validateToken(String token) {
              try {
                  Jwts.parser().setSigningKey(secret).parseClaimsJws(token);
                  return true;
              } catch (Exception ex) {
                  return false;
              }
          }
      
          /**
           * 从token中获取用户名
           */
          public static String getUsername(String token) {
              Claims claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
              return claims.get("username", String.class);
          }
      
          /**
           * 从token中获取用户角色
           */
          public static List<String> getRoles(String token) {
              Claims claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
              List<String> roles = (List<String>) claims.get("roles", List.class);
              return roles;
          }
      }
      
      // 配置JWT的过滤器
      public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
      
          @Override
          protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
              String token = httpServletRequest.getHeader("Authorization");
              if (token != null && token.startsWith("Bearer ")) {
                  token = token.substring(7);
              }
              if (token != null && JwtTokenUtils.validateToken(token)) {
                  String username = JwtTokenUtils.getUsername(token);
                  List<String> roles = JwtTokenUtils.getRoles(token);
                  UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(username, null, roles.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList()));
                  SecurityContextHolder.getContext().setAuthentication(authentication);
              }
              filterChain.doFilter(httpServletRequest, httpServletResponse);
          }
      }
      
      // 配置权限管理器
      @Configuration
      @EnableWebSecurity
      public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
      
          @Autowired
          private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
      
          @Override
          protected void configure(HttpSecurity http) throws Exception {
              http.csrf().disable()
                  .addFilterAfter(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class)
                  .authorizeRequests()
                  .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
                  .antMatchers("/api/authenticate").permitAll()
                  .anyRequest().authenticated();
          }
      
          @Override
          public void configure(AuthenticationManagerBuilder auth) throws Exception {
              auth.userDetailsService(loginUserDetailsService);
          }
      
          @Bean
          @Override
          public AuthenticationManager authenticationManagerBean() throws Exception {
              return super.authenticationManagerBean();
          }
      }
      
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

问题事件

  • 系统已结题 8月12日
  • 已采纳回答 8月4日
  • 创建了问题 5月11日

悬赏问题

  • ¥15 运动想象脑电信号数据集.vhdr
  • ¥15 三因素重复测量数据R语句编写,不存在交互作用
  • ¥15 微信会员卡等级和折扣规则
  • ¥15 微信公众平台自制会员卡可以通过收款码收款码收款进行自动积分吗
  • ¥15 随身WiFi网络灯亮但是没有网络,如何解决?
  • ¥15 gdf格式的脑电数据如何处理matlab
  • ¥20 重新写的代码替换了之后运行hbuliderx就这样了
  • ¥100 监控抖音用户作品更新可以微信公众号提醒
  • ¥15 UE5 如何可以不渲染HDRIBackdrop背景
  • ¥70 2048小游戏毕设项目