三江统一登录更改

This commit is contained in:
GUO 2023-03-28 08:41:16 +08:00
parent e204640f2e
commit 573295d316
2 changed files with 107 additions and 56 deletions

View File

@ -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:C2ATC2RT返回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"));
}

View File

@ -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<JwtPayloadUserInfo> 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<SystemUser>().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;
}
/**