package com.vincent.rsf.server.common.security; import com.vincent.rsf.framework.common.Cools; import com.vincent.rsf.server.common.config.ConfigProperties; import com.vincent.rsf.server.common.constant.Constants; import com.vincent.rsf.server.common.utils.CommonUtil; import com.vincent.rsf.server.common.utils.JwtUtil; import com.vincent.rsf.server.system.entity.Menu; import com.vincent.rsf.server.system.entity.User; import com.vincent.rsf.server.system.entity.UserLogin; import com.vincent.rsf.server.system.service.UserLoginService; import com.vincent.rsf.server.system.service.UserService; import io.jsonwebtoken.Claims; import io.jsonwebtoken.ExpiredJwtException; import lombok.extern.slf4j.Slf4j; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; import javax.annotation.Resource; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.stream.Collectors; /** * 处理携带token的请求过滤器 * */ @Slf4j @Component public class JwtAuthenticationFilter extends OncePerRequestFilter { public static final ArrayList WHITE_KEY = new ArrayList(){ private static final long serialVersionUID = 1L; { add("xltys1995"); } }; @Resource private ConfigProperties configProperties; @Resource private UserService userService; @Resource private UserLoginService userLoginService; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { String access_token = JwtUtil.getAccessToken(request); for (String filterPath : SecurityConfig.FILTER_PATH) { AntPathRequestMatcher antPathMatcher = new AntPathRequestMatcher(filterPath); if (antPathMatcher.matches(request)) { access_token = ""; } } if (!Cools.isEmpty(access_token)) { try { User user; if (WHITE_KEY.contains(access_token)) { user = userService.getByUsername("root", 1L); if (user == null) { throw new UsernameNotFoundException("Username not found"); } userService.setUserAuthInfo(user); List authorities = user.getAuthorities().stream() .filter(m -> !Cools.isEmpty(m.getAuthority())).collect(Collectors.toList()); UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( user, null, authorities); SecurityContextHolder.getContext().setAuthentication(authentication); } else { // 解析token Claims claims = JwtUtil.parseToken(access_token, configProperties.getTokenKey()); JwtSubject jwtSubject = JwtUtil.getJwtSubject(claims); user = userService.getByUsername(jwtSubject.getUsername(), jwtSubject.getTenantId()); if (user == null) { throw new UsernameNotFoundException("Username not found"); } userService.setUserAuthInfo(user); List authorities = user.getAuthorities().stream() .filter(m -> !Cools.isEmpty(m.getAuthority())).collect(Collectors.toList()); UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( user, null, authorities); SecurityContextHolder.getContext().setAuthentication(authentication); // token将要过期签发新token, 防止突然退出登录 long expiration = (claims.getExpiration().getTime() - new Date().getTime()) / 1000 / 60; if (expiration < configProperties.getTokenRefreshTime()) { String token = JwtUtil.buildToken(jwtSubject, configProperties.getTokenExpireTime(), configProperties.getTokenKey()); response.addHeader(Constants.TOKEN_HEADER_NAME, token); userLoginService.saveAsync(user.getId(), token, UserLogin.TYPE_REFRESH, user.getTenantId(), null, request); } } } catch (ExpiredJwtException e) { log.error("JwtAuthenticationFilter ExpiredJwtException", e); CommonUtil.responseError(response, Constants.TOKEN_EXPIRED_CODE, Constants.TOKEN_EXPIRED_MSG, e.getMessage()); return; } catch (Exception e) { log.error("JwtAuthenticationFilter", e); CommonUtil.responseError(response, Constants.BAD_CREDENTIALS_CODE, Constants.BAD_CREDENTIALS_MSG, e.toString()); return; } } chain.doFilter(request, response); } }