diff --git a/src/main/java/com/zhgd/xmgl/modules/basicdata/controller/SjLoginController.java b/src/main/java/com/zhgd/xmgl/modules/basicdata/controller/SjLoginController.java index e03cd113c..385276471 100644 --- a/src/main/java/com/zhgd/xmgl/modules/basicdata/controller/SjLoginController.java +++ b/src/main/java/com/zhgd/xmgl/modules/basicdata/controller/SjLoginController.java @@ -1,24 +1,28 @@ package com.zhgd.xmgl.modules.basicdata.controller; +import com.gexin.fastjson.JSON; import com.zhgd.jeecg.common.api.vo.Result; import com.zhgd.xmgl.entity.sj.JwtPayloadUserInfo; import com.zhgd.xmgl.entity.sj.TokenResponse; import com.zhgd.xmgl.modules.basicdata.service.impl.SystemUserServiceImpl; import com.zhgd.xmgl.util.MessageUtil; -import com.zhgd.xmgl.util.sj.CookieUtils; import com.zhgd.xmgl.util.sj.JwtRsaUtils; import com.zhgd.xmgl.util.sj.SjUnifiedAuthenticationHttpUtil; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.security.spec.InvalidKeySpecException; +import java.util.concurrent.TimeUnit; /** * 三江统一登录 @@ -31,6 +35,9 @@ public class SjLoginController { private SjUnifiedAuthenticationHttpUtil sjUnifiedAuthenticationHttpUtil; @Autowired private SystemUserServiceImpl systemUserService; + @Autowired + private StringRedisTemplate redisTemplate; + public static String SJ_TOKEN_PREFIX = "SJ_UNIFIEDAUTHENTICATION_TOKEN:"; /** * 根据code获取token @@ -41,16 +48,19 @@ public class SjLoginController { * @throws IOException */ @GetMapping("/getTokenByCode") - public void getTokenByCode(@RequestParam String code, HttpServletResponse response, HttpServletRequest request) throws IOException { + public void getTokenByCode(@RequestParam String code, HttpServletResponse response, HttpServletRequest request) throws IOException, InvalidKeySpecException { //根据授权码获取令牌 log.info("code:{}", code); TokenResponse tokenByCode = sjUnifiedAuthenticationHttpUtil.getTokenByCode(code); //⑦将获取到的用户凭证(access_token)值存储到cookie中,名称可定为C2AT,获取到的用户刷新凭证(refresh_token)值存储到cookie中,名称为C2RT,接口返回307,重定向到应用页面(一般为首页) String access_token = tokenByCode.getAccess_token(); - CookieUtils.setCookie(request, response, "C2AT", access_token, Integer.valueOf(tokenByCode.getExpires_in()), "UTF-8", - false, "192.168.34.150:8080", "/"); - CookieUtils.setCookie(request, response, "C2RT", tokenByCode.getRefresh_token(), Integer.valueOf(tokenByCode.getRe_expires_in()), "UTF-8", false, - "192.168.34.150:8080", "/"); + if (access_token != null) { + JwtPayloadUserInfo jwtPayloadUserInfo = JwtRsaUtils.verifyWithUserInfo(access_token); + if (StringUtils.isNotBlank(access_token)) { + redisTemplate.opsForValue().set(SJ_TOKEN_PREFIX + jwtPayloadUserInfo.getAc(), JSON.toJSONString(tokenByCode) + , Long.parseLong(tokenByCode.getRe_expires_in()), TimeUnit.SECONDS); + } + } //获取用户信息 //重定向到应用页面(一般为首页) response.sendRedirect("http://192.168.34.150:8080/index.html#/login?UID=" + access_token); @@ -67,8 +77,6 @@ public class SjLoginController { public void logout(HttpServletRequest request, HttpServletResponse response) throws IOException { log.info("logout"); //④清除本地请求头request里面存储的cookie:C2AT、C2RT,返回302重定向到应用页面 - CookieUtils.setCookie(request, response, "C2AT", "", 0); - CookieUtils.setCookie(request, response, "C2RT", "", 0); //重定向到应用页面(一般为首页) response.sendRedirect("/index.html#/"); @@ -77,14 +85,16 @@ public class SjLoginController { /** * 根据token获取用户登录信息 * - * @param uid jwt_token + * @param uid jwt_token 统一登录token * @return */ @GetMapping("getLoginInfoByToken") + @ResponseBody public Result getLoginInfoByToken(@RequestParam String uid) throws InvalidKeySpecException { JwtPayloadUserInfo jwtPayloadUserInfo = JwtRsaUtils.verifyWithUserInfo(uid); if (jwtPayloadUserInfo != null) { - return systemUserService.sjLogin(jwtPayloadUserInfo); + Result result = systemUserService.sjLogin(jwtPayloadUserInfo); + return result; } return Result.error(MessageUtil.get("systemErr")); } diff --git a/src/main/java/com/zhgd/xmgl/security/JwtTokenFilter.java b/src/main/java/com/zhgd/xmgl/security/JwtTokenFilter.java index a313d8f02..9d2606836 100644 --- a/src/main/java/com/zhgd/xmgl/security/JwtTokenFilter.java +++ b/src/main/java/com/zhgd/xmgl/security/JwtTokenFilter.java @@ -1,19 +1,24 @@ package com.zhgd.xmgl.security; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.gexin.fastjson.JSON; import com.zhgd.exception.CustomException; import com.zhgd.xmgl.entity.sj.JwtPayloadUserInfo; import com.zhgd.xmgl.entity.sj.TokenResponse; +import com.zhgd.xmgl.modules.basicdata.entity.SystemUser; +import com.zhgd.xmgl.modules.basicdata.mapper.SystemUserMapper; import com.zhgd.xmgl.util.ProfileJudgeUtil; -import com.zhgd.xmgl.util.sj.CookieUtils; import com.zhgd.xmgl.util.sj.JwtRsaUtils; import com.zhgd.xmgl.util.sj.SjUnifiedAuthenticationHttpUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.HttpStatus; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; @@ -23,7 +28,10 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.security.spec.InvalidKeySpecException; -import java.util.Arrays; +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +import static com.zhgd.xmgl.modules.basicdata.controller.SjLoginController.SJ_TOKEN_PREFIX; /** * @program: devManage @@ -41,6 +49,10 @@ public class JwtTokenFilter extends OncePerRequestFilter { private boolean securityEnable; @Autowired private SjUnifiedAuthenticationHttpUtil sjUnifiedAuthenticationHttpUtil; + @Autowired + private SystemUserMapper systemUserMapper; + @Autowired + private StringRedisTemplate redisTemplate; public static ThreadLocal sjUser = new ThreadLocal<>(); @@ -54,14 +66,11 @@ public class JwtTokenFilter extends OncePerRequestFilter { //三江统一认证,3.登录:过滤器判断,回调地址获取code调用获取令牌,首页根据令牌获取登录数据信息 if (ProfileJudgeUtil.isSjjtGsx()) { try { - //验证不通过不放行 - boolean b = validateSjProfile(request, response, filterChain); - if (!b) { - return; - } + validateSjProfile(request, response, filterChain); } catch (InvalidKeySpecException e) { log.error("认证失败ex::", e); - return; + } catch (CustomException e) { + throw new RuntimeException("认证失败"); } } else { @@ -82,37 +91,72 @@ public class JwtTokenFilter extends OncePerRequestFilter { * @throws IOException * @throws ServletException */ - private boolean validateSjProfile(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws InvalidKeySpecException, IOException, ServletException { - //不拦截url - String permitUrls = "xmgl/sj/unifiedAuthentication/logout,xmgl/sj/unifiedAuthentication/getTokenByCode,xmgl/sj/unifiedAuthentication/getLoginInfoByToken"; - if (Arrays.asList(permitUrls.split(",")).stream().anyMatch(s -> request.getRequestURL().toString().contains(s))) { - return true; + private void validateSjProfile(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws InvalidKeySpecException, IOException, ServletException { + //不传统一登录获取的token给前端,用之前的token + //校验token + String token = jwtTokenProvider.resolveToken(request); + if (token == null) { + return; } + if (jwtTokenProvider.validateToken(token)) { + Authentication auth = jwtTokenProvider.getAuthentication(token); + //判断用户类型,统一登录还是这边登录的 + String account = auth.getName(); + SystemUser systemUser = systemUserMapper.selectOne(new LambdaQueryWrapper().eq(SystemUser::getAccount, account)); + //统一登录的,redis中维护统一登录token + Integer accountType = systemUser.getAccountType(); + if (Objects.equals(accountType, 2) || Objects.equals(accountType, 3) + || Objects.equals(accountType, 4) || Objects.equals(accountType, 5)) { + //统一登录 + String tokenDetails = redisTemplate.opsForValue().get(SJ_TOKEN_PREFIX + account); + TokenResponse tokenResponse = JSON.parseObject(tokenDetails, TokenResponse.class); + String c2AT = tokenResponse.getAccess_token(); + String c2rt = tokenResponse.getRefresh_token(); + //②应用过滤器中判断请求头request中是否含有C2AT(若C2AT存在,C2AT的校验、过期更新请参考凭证更新令牌流程) + //C2AT不存在,且更新令牌失败,则返回401,并在Location中带上登录页面地址,登录页面地址在应用过滤器中拼装,拼装方式请参考3.1.1获取授权码接口地址 + JwtPayloadUserInfo jwtPayloadUserInfo = null; + if (StringUtils.isNotBlank(c2AT)) { + //C2AT的校验 + //1.判断是否过期 + //2.令牌校验 + jwtPayloadUserInfo = JwtRsaUtils.verifyWithUserInfo(c2AT); + sjUser.set(jwtPayloadUserInfo); + //token校验失败,先尝试刷新token,失败就重定向统一登录 + if (jwtPayloadUserInfo == null) { + tryRefreshToken(request, response); + } else { + setSjAuthenticationToken(jwtPayloadUserInfo); + } + } else if (StringUtils.isNotBlank(c2rt)) { + tryRefreshToken(request, response); + } - //②应用过滤器中判断请求头request中是否含有C2AT(若C2AT存在,C2AT的校验、过期更新请参考凭证更新令牌流程) - //C2AT不存在,且更新令牌失败,则返回401,并在Location中带上登录页面地址,登录页面地址在应用过滤器中拼装,拼装方式请参考3.1.1获取授权码接口地址 - String c2AT = request.getHeader("C2AT"); - String c2rt = request.getHeader("C2RT"); - JwtPayloadUserInfo jwtPayloadUserInfo = null; - if (StringUtils.isNotBlank(c2AT)) { - //C2AT的校验 - //1.判断是否过期 - //2.令牌校验 - jwtPayloadUserInfo = JwtRsaUtils.verifyWithUserInfo(c2AT); - sjUser.set(jwtPayloadUserInfo); - //token校验失败,先尝试刷新token,失败就重定向统一登录 - if (jwtPayloadUserInfo == null) { - return tryRefreshToken(request, response); + } else { + //我们这边调用我们这么认证 + SecurityContextHolder.getContext().setAuthentication(auth); } - } else if (StringUtils.isNotBlank(c2rt)) { - return tryRefreshToken(request, response); - } else { - //C2AT和C2RT都不存在 - //重定向登录页面 - //获取授权码,客户端申请授权的URI,在浏览器中以GET请求发送到认证服务器: - throw new CustomException("Unauthorized", HttpStatus.UNAUTHORIZED); } - return true; + } + + /** + * 认证方法 + * + * @param jwtPayloadUserInfo + */ + private void setSjAuthenticationToken(JwtPayloadUserInfo jwtPayloadUserInfo) { + if (jwtPayloadUserInfo != null) { + UserDetails uds = org.springframework.security.core.userdetails.User// + .withUsername(jwtPayloadUserInfo.getAc())// + .password("$2a$12$LEfaQ8x1lPhxnOl3bh7hreI9o5DlV0NxDNZyazH50oji3kFE33QEi")// + .accountExpired(false)// + .accountLocked(false)// + .credentialsExpired(false)// + .authorities("admin") + .disabled(false)// + .build(); + Authentication auth = new UsernamePasswordAuthenticationToken(uds, "", null); + SecurityContextHolder.getContext().setAuthentication(auth); + } } /** @@ -123,22 +167,19 @@ public class JwtTokenFilter extends OncePerRequestFilter { * @return * @throws IOException */ - private boolean tryRefreshToken(HttpServletRequest request, HttpServletResponse response) throws IOException { + private void tryRefreshToken(HttpServletRequest request, HttpServletResponse response) throws IOException, InvalidKeySpecException { String c2rt = request.getHeader("C2RT"); if (StringUtils.isNotBlank(c2rt)) { //刷新token - TokenResponse rs = sjUnifiedAuthenticationHttpUtil.refreshToken(c2rt); + TokenResponse tokenByCode = sjUnifiedAuthenticationHttpUtil.refreshToken(c2rt); //刷新token成功 - if (rs.getErrorCode() == null) { - CookieUtils.setCookie(request, response, "C2AT", rs.getAccess_token(), Integer.valueOf(rs.getExpires_in())); - CookieUtils.setCookie(request, response, "C2RT", rs.getRefresh_token(), Integer.valueOf(rs.getRe_expires_in())); - return true; - } else { - //刷新token失败,重定向登录页面 - throw new CustomException("Unauthorized", HttpStatus.UNAUTHORIZED); + if (tokenByCode.getErrorCode() == null) { + JwtPayloadUserInfo jwtPayloadUserInfo = JwtRsaUtils.verifyWithUserInfo(tokenByCode.getAccess_token()); + setSjAuthenticationToken(jwtPayloadUserInfo); + redisTemplate.opsForValue().set(SJ_TOKEN_PREFIX + jwtPayloadUserInfo.getAc(), JSON.toJSONString(tokenByCode) + , Long.parseLong(tokenByCode.getRe_expires_in()), TimeUnit.SECONDS); } } - return false; } /**