那人好像一条狗.. 2019-12-11 17:33 采纳率: 100%
浏览 3062
已采纳

关于Spring boot + SpringSecurity +jwt token失效的问题

比如我登abc的用户,然后我在另一个地点也登abc的用户,那前一个登陆的在刷新或者请求接口的时候要登出,
或者是我后台改了abc的密码,那abc这个账户在刷新请求接口的时候要登出。
框架我搭好了 代码如下:
生成token工具类:


public class JwtTokenUtil {

    private static InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("jwt.jks"); // 寻找证书文件
    private static PrivateKey privateKey = null;
    private static PublicKey publicKey = null;

    static { // 将证书文件里边的私钥公钥拿出来
        try {
            KeyStore keyStore = KeyStore.getInstance("JKS"); // java key store 固定常量
            keyStore.load(inputStream, "123456".toCharArray());
            privateKey = (PrivateKey) keyStore.getKey("jwt", "123456".toCharArray()); // jwt 为 命令生成整数文件时的别名
            publicKey = keyStore.getCertificate("jwt").getPublicKey();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static String generateToken(String subject, int expirationSeconds, String salt) {
        return Jwts.builder()
                .setClaims(null)
                .setSubject(subject)
                .setExpiration(new Date(System.currentTimeMillis() + expirationSeconds * 1000))
//                .signWith(SignatureAlgorithm.HS512, salt) // 不使用公钥私钥
                .signWith(SignatureAlgorithm.RS256, privateKey)
                .compact();
    }

    public static String parseToken(String token, String salt) {
        String subject = null;
        try {
            Claims claims = Jwts.parser()
//                    .setSigningKey(salt) // 不使用公钥私钥
                    .setSigningKey(publicKey)
                    .parseClaimsJws(token).getBody();
            subject = claims.getSubject();
        } catch (Exception e) {
        }
        return subject;
    }

}

登陆成功后生成JTWtoken :



    @Component
    public class AjaxAuthenticationSuccessHandler implements AuthenticationSuccessHandler {

        @Override
        public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
            ResponseBase responseBase = new ResponseBase();
            responseBase.setCode("200");
            responseBase.setMassage("Login Success!");
            String jwtToken = JwtTokenUtil.generateToken(String.valueOf(authentication.getPrincipal()), 300, "_secret");
            responseBase.setJwtToken(jwtToken);
            httpServletResponse.getWriter().write(JSON.toJSONString(responseBase));
        }
}

监听器:




@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {

    @Autowired
    AdminSysUserSecurityService adminSysUserSecurityService;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
        String authHeader = request.getHeader("Authorization");

        if (authHeader != null && authHeader.startsWith("Bearer ")) {
            final String authToken = authHeader.substring("Bearer ".length());

            String username = JwtTokenUtil.parseToken(authToken, "_secret");

            if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
                UserDetails userDetails = adminSysUserSecurityService.loadUserByUsername(username);

                if (userDetails != null) {
                    UsernamePasswordAuthenticationToken authentication =
                            new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                    authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));

                    SecurityContextHolder.getContext().setAuthentication(authentication);
                }
            }
        }

        chain.doFilter(request, response);
    }
}

@Component("rbacauthorityservice")
public class RbacAuthorityService {
    public boolean hasPermission(HttpServletRequest request, Authentication authentication) {

        Object userInfo = authentication.getPrincipal();

        boolean hasPermission  = false;

        if (userInfo instanceof UserDetails) {

            String username = ((UserDetails) userInfo).getUsername();

            //获取资源
            Set<String> urls = new HashSet();
            urls.add("/**/**"); // 这些 url 都是要登录后才能访问,且其他的 url 都不能访问!
            Set set2 = new HashSet();
            Set set3 = new HashSet();

            AntPathMatcher antPathMatcher = new AntPathMatcher();

            for (String url : urls) {
                if (antPathMatcher.match(url, request.getRequestURI())) {
                    hasPermission = true;
                    break;
                }
            }

            return hasPermission;
        } else {
            return false;
        }
    }
}

配置:


@Configuration
public class AdminWebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Value("${pay.strength}")
    private int strength;
    @Autowired
    private  AdminSysUserSecurityService adminSysUserSecurityService;

    @Bean
    public PasswordEncoder passwordEncoder(){
//        return NoOpPasswordEncoder.getInstance();//不对密码加密
        return  new BCryptPasswordEncoder(strength);//秘钥迭代次数为 2^strength,strength取值在 4-31 之间,默认10
    }

    @Autowired
    AjaxAuthenticationEntryPoint authenticationEntryPoint;  //  未登陆时返回 JSON 格式的数据给前端(否则为 html)

    @Autowired
    AjaxAuthenticationSuccessHandler authenticationSuccessHandler;  // 登录成功返回的 JSON 格式数据给前端(否则为 html)

    @Autowired
    AjaxAuthenticationFailureHandler authenticationFailureHandler;  //  登录失败返回的 JSON 格式数据给前端(否则为 html)

    @Autowired
    AjaxLogoutSuccessHandler  logoutSuccessHandler;  // 注销成功返回的 JSON 格式数据给前端(否则为 登录时的 html)

    @Autowired
    AjaxAccessDeniedHandler accessDeniedHandler;    // 无权访问返回的 JSON 格式数据给前端(否则为 403 html 页面)

    @Autowired
    JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter; // JWT 拦截器

    @Autowired
    SelfAuthenticationProvider provider; // 自定义安全认证

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 加入自定义的安全认证
        auth.authenticationProvider(provider);
    }

    @Override
    public void configure(HttpSecurity http)throws Exception{
        //开启HttpSecurity配置
        http.csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) // 使用 JWT,关闭token
                .and()
                .httpBasic().authenticationEntryPoint(authenticationEntryPoint)
                .and()
                .authorizeRequests()
//                .antMatchers("/db/**").hasRole("DB")
//                .antMatchers("/user/**").hasRole("USER")
//                .antMatchers("/admin/**").hasRole("ADMIN")
//                .antMatchers("/user/**").access("hasAnyRole('ADMIN','ROOT')")
//                .antMatchers("/db/**").access("hasAnyRole('ADMIN') and hasRole('DBA')")
                //除了前面路径,用户访问其他URL都必须认证后访问
                .anyRequest()
                .access("@rbacauthorityservice.hasPermission(request,authentication)") // RBAC 动态 url 认证
                .and()
                //开启表单登录,同事配置了登入接口为/login
                .formLogin()
               /* //该接口主要方便ajax或者移动端登入
                .loginProcessingUrl("/login")
                //设置登录成功跳转页面,error=true控制页面错误信息的展示
                .successForwardUrl("/index").failureUrl("/login?error=true")
            */    //登入接口都不需要认证
                .successHandler(authenticationSuccessHandler) // 登录成功
                .failureHandler(authenticationFailureHandler) // 登录失败
                .permitAll()
                .and()
                //开启注销登入配置
                .logout()
                .logoutSuccessHandler(logoutSuccessHandler)
                .permitAll();


        http.rememberMe().rememberMeParameter("remember-me")
                .userDetailsService(adminSysUserSecurityService).tokenValiditySeconds(300);

        http.exceptionHandling().accessDeniedHandler(accessDeniedHandler); // 无权访问 JSON 格式的数据
        http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); // JWT Filter


    }

登陆成功后获取token,postman测试:
图片说明
可以

但是我重新调用新的登陆接口,相同用户名获取新的token后,原来的token依旧可以请求。
所以要在哪边配置 用户其它地方登陆,或者用户密码变更,jtwtoken失效

  • 写回答

2条回答

  • qbanxiaoli 2019-12-15 00:18
    关注

    jwt的非对称加密是通过私钥签名,公钥验签的,因为服务端没有存储,jwt一旦签发,只要没过期就可以一直使用的,除非你把jwt也存redis里面再进行一次拦截判断

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 教务系统账号被盗号如何追溯设备
  • ¥20 delta降尺度方法,未来数据怎么降尺度
  • ¥15 c# 使用NPOI快速将datatable数据导入excel中指定sheet,要求快速高效
  • ¥15 再不同版本的系统上,TCP传输速度不一致
  • ¥15 高德地图点聚合中Marker的位置无法实时更新
  • ¥15 DIFY API Endpoint 问题。
  • ¥20 sub地址DHCP问题
  • ¥15 delta降尺度计算的一些细节,有偿
  • ¥15 Arduino红外遥控代码有问题
  • ¥15 数值计算离散正交多项式