You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
537 lines
22 KiB
537 lines
22 KiB
package com.fr.plugin.nfsq.sso; |
|
|
|
import com.fr.base.TemplateUtils; |
|
import com.fr.data.NetworkHelper; |
|
import com.fr.decision.authority.data.User; |
|
import com.fr.decision.fun.impl.AbstractGlobalRequestFilterProvider; |
|
import com.fr.decision.mobile.terminal.TerminalHandler; |
|
import com.fr.decision.webservice.bean.authentication.LoginRequestInfoBean; |
|
import com.fr.decision.webservice.exception.user.UserNotExistException; |
|
import com.fr.decision.webservice.utils.DecisionServiceConstants; |
|
import com.fr.decision.webservice.utils.DecisionStatusService; |
|
import com.fr.decision.webservice.v10.login.LoginService; |
|
import com.fr.decision.webservice.v10.login.TokenResource; |
|
import com.fr.decision.webservice.v10.user.UserService; |
|
import com.fr.general.http.HttpRequest; |
|
import com.fr.general.http.HttpToolbox; |
|
import com.fr.io.utils.ResourceIOUtils; |
|
import com.fr.json.JSONObject; |
|
import com.fr.log.FineLoggerFactory; |
|
import com.fr.plugin.transform.FunctionRecorder; |
|
import com.fr.stable.StringUtils; |
|
import com.fr.stable.web.Device; |
|
import com.fr.web.utils.WebUtils; |
|
|
|
import javax.servlet.FilterChain; |
|
import javax.servlet.ServletException; |
|
import javax.servlet.http.Cookie; |
|
import javax.servlet.http.HttpServletRequest; |
|
import javax.servlet.http.HttpServletResponse; |
|
import java.io.BufferedReader; |
|
import java.io.IOException; |
|
import java.io.InputStream; |
|
import java.io.UnsupportedEncodingException; |
|
import java.net.URLEncoder; |
|
import java.time.Instant; |
|
import java.util.*; |
|
import java.util.regex.Pattern; |
|
import java.util.stream.Collectors; |
|
import java.util.stream.Stream; |
|
|
|
/** |
|
* @Author fr.open |
|
* @Date 2020/9/10 |
|
* @Description |
|
**/ |
|
@FunctionRecorder |
|
public class SsoFilter extends AbstractGlobalRequestFilterProvider { |
|
|
|
private final String CODE_KEY = "90bb6046"; |
|
|
|
@Override |
|
public String filterName() { |
|
return "nongfu"; |
|
} |
|
|
|
@Override |
|
public String[] urlPatterns() { |
|
return new String[]{"/*"}; |
|
} |
|
|
|
private static final String[] NOT_FILTER = { |
|
"/decision/file", |
|
"/decision/resources", |
|
"/system", |
|
"/materials.min.js.map", |
|
"/remote", |
|
"/login", |
|
"/login/config", |
|
"/getFineToken" |
|
}; |
|
|
|
private String apiAuthorize; |
|
|
|
private String apiAuthorizeResponseType; |
|
|
|
private String apiClientId; |
|
|
|
private String apiGetUser; |
|
|
|
private String apiRefreshToken; |
|
|
|
private String state; |
|
|
|
public SsoFilter() { |
|
InputStream in = ResourceIOUtils.read("/resources/xplatform.properties"); |
|
Properties properties = new Properties(); |
|
try { |
|
properties.load(in); |
|
} catch (IOException e) { |
|
FineLoggerFactory.getLogger().error(e.getMessage(),e); |
|
} |
|
this.apiAuthorize = properties.getProperty("api.authorize"); |
|
this.apiClientId = properties.getProperty("api.authorize.client_id"); |
|
this.apiAuthorizeResponseType = properties.getProperty("api.authorize.response_type"); |
|
this.apiGetUser = properties.getProperty("api.get-user"); |
|
this.apiRefreshToken = properties.getProperty("api.refresh-token"); |
|
this.state = properties.getProperty("api.authorize.state"); |
|
} |
|
|
|
|
|
@Override |
|
public void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain filterChain) { |
|
String thisUrl = req.getRequestURL().toString(); |
|
FineLoggerFactory.getLogger().info("This request [{}] login status is [{}]", thisUrl, isLogin(req)); |
|
if (req.getRequestURI().endsWith("auth")) { |
|
executeGetAuth(req, res); |
|
return; |
|
} |
|
String code = req.getParameter("sign"); |
|
if (StringUtils.isNotBlank(code)) { |
|
loginFromCode(code, req, res); |
|
filter(req, res, filterChain); |
|
return; |
|
} |
|
if (Stream.of(NOT_FILTER).anyMatch(thisUrl::contains) || isLogin(req) || isMobileDevice(req)) { |
|
filter(req, res, filterChain); |
|
return; |
|
} |
|
String prefix = null; |
|
try { |
|
prefix = TemplateUtils.render("${fineServletURL}"); |
|
if (req.getRequestURI().endsWith(prefix + "/login")) { |
|
if (handlerWeChat(req, res)) { |
|
return; |
|
} |
|
filter(req, res, filterChain); |
|
return; |
|
} |
|
|
|
}catch (IllegalAccessException e){ |
|
redirectAuth(req, res); |
|
return; |
|
}catch (Exception e) { |
|
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
|
} |
|
Params params = null; |
|
try { |
|
params = getUsername(req); |
|
} catch (IllegalAccessException e) { |
|
redirectAuth(req, res); |
|
return; |
|
} |
|
FineLoggerFactory.getLogger().info("Getted username is [{}]", params.getUsername()); |
|
if (StringUtils.isNotBlank(params.getUsername())) { |
|
Cookie at = new Cookie("access_token", params.getAccessToken()); |
|
at.setDomain("xxxx"); |
|
at.setMaxAge(7200); |
|
Cookie rt = new Cookie("refresh_token", params.getRefreshToken()); |
|
rt.setDomain("xxxx"); |
|
rt.setMaxAge(7200); |
|
res.addCookie(at); |
|
res.addCookie(rt); |
|
loginFromToken(req, res, params.getUsername()); |
|
try { |
|
res.sendRedirect(getRedirectUriWithCachedParams(req)); |
|
} catch (IOException e) { |
|
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
|
} |
|
return; |
|
} |
|
redirectAuth(req, res); |
|
} |
|
|
|
private void redirectAuth(HttpServletRequest req, HttpServletResponse res) { |
|
try { |
|
res.sendRedirect(getAuthorizeUrl(req,res)); |
|
} catch (IOException e) { |
|
FineLoggerFactory.getLogger().error(e.getMessage(),e); |
|
} |
|
} |
|
|
|
private boolean handlerWeChat(HttpServletRequest request, HttpServletResponse res) throws IOException, IllegalAccessException { |
|
// 有帆软的登录信息 |
|
if (isLogin(request)) { |
|
FineLoggerFactory.getLogger().info("/decision请求特殊处理 >>> 已登录"); |
|
String token = getAccessToken(request); |
|
FineLoggerFactory.getLogger().info("/decision请求特殊处理 >>> token value is [{}]", token); |
|
// 没有获取到access_token |
|
if (StringUtils.isBlank(token)) { |
|
FineLoggerFactory.getLogger().info("/decision请求特殊处理 >>> token value is empty, 不做处理"); |
|
return false; |
|
} |
|
// 获取到了access_token, 比对帆软已登录的用户名和access_token对应的用户名 |
|
String username = getUsername(request, token).getUsername(); |
|
FineLoggerFactory.getLogger().info("/decision请求特殊处理 >>> token 对应的用户名[{}]", username); |
|
String username1 = LoginService.getInstance().getUserNameFromRequestCookie(request); |
|
FineLoggerFactory.getLogger().info("/decision请求特殊处理 >>> 已登录的用户名[{}]", username1); |
|
if (Objects.equals(username1, username)) { |
|
FineLoggerFactory.getLogger().info("/decision请求特殊处理 >>> 两个用户名相同, 不做处理"); |
|
return false; |
|
} |
|
// 不一样的话使用access_token对应的用户名重新登录 |
|
FineLoggerFactory.getLogger().info("/decision请求特殊处理 >>> 两个用户名不相同, 使用[{}]重新登录", username); |
|
loginFromToken(request, res, username); |
|
return false; |
|
} |
|
|
|
// 没有登录信息 |
|
FineLoggerFactory.getLogger().info("/decision请求特殊处理 >>> 未登录"); |
|
String token = getAccessToken(request); |
|
FineLoggerFactory.getLogger().info("/decision请求特殊处理 >>> token value is [{}]", token); |
|
if (StringUtils.isNotBlank(token)) { |
|
FineLoggerFactory.getLogger().info("/decision请求特殊处理 >>> token value is not empty, 处理自动登录逻辑"); |
|
Params params = getUsername(request, token); |
|
FineLoggerFactory.getLogger().info("/decision请求特殊处理 >>> 获取到的用户名[{}]", params.getUsername()); |
|
if (StringUtils.isNotBlank(params.getUsername()) && exist(params.getUsername())) { |
|
Cookie at = new Cookie("access_token", params.getAccessToken()); |
|
at.setDomain("yst.com.cn"); |
|
Cookie rt = new Cookie("refresh_token", params.getRefreshToken()); |
|
rt.setDomain("yst.com.cn"); |
|
loginFromToken(request, res, params.getUsername()); |
|
res.sendRedirect(getRedirectUriWithCachedParams(request)); |
|
return true; |
|
} |
|
} |
|
FineLoggerFactory.getLogger().info("/decision请求特殊处理 >>> token value is empty, 跳转到sso登录页"); |
|
res.sendRedirect(getAuthorizeUrl(request, res)); |
|
return true; |
|
} |
|
|
|
private String getAuthorizeUrl(HttpServletRequest request, HttpServletResponse res) throws UnsupportedEncodingException { |
|
String urlPattern = "%s?response_type=%s&client_id=%s&redirect_uri=%s&_=%s&state=%s"; |
|
String state = cacheParams(request); |
|
res.addCookie(new Cookie("FINE_REDIRECT_PARAM",state)); |
|
if (StringUtils.isNotBlank(state)) { |
|
urlPattern += "&target=" + state; |
|
} |
|
String url = String.format(urlPattern, |
|
apiAuthorize, |
|
apiAuthorizeResponseType, |
|
apiClientId, |
|
URLEncoder.encode(request.getRequestURL().toString(), "utf-8"), |
|
Instant.now().toEpochMilli(), |
|
this.state |
|
); |
|
FineLoggerFactory.getLogger().info("授权登录页面[{}]", url); |
|
return url; |
|
} |
|
|
|
private String cacheParams(HttpServletRequest request) { |
|
Enumeration<String> names = request.getParameterNames(); |
|
Map<String, String> value = new HashMap<>(); |
|
while (names.hasMoreElements()) { |
|
String name = names.nextElement(); |
|
value.put(name, request.getParameter(name)); |
|
} |
|
if (value.isEmpty()) { |
|
return StringUtils.EMPTY; |
|
} |
|
String key = UUID.randomUUID().toString(); |
|
try { |
|
DecisionStatusService.originUrlStatusService().put(key, value); |
|
} catch (Exception e) { |
|
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
|
} |
|
return key; |
|
} |
|
|
|
/** |
|
* 登录成功后将缓存中存储的url参数拼接入对应地址 |
|
* |
|
* @param request |
|
* @return |
|
*/ |
|
|
|
|
|
private String getRedirectUriWithCachedParams(HttpServletRequest request) { |
|
String redirectUri = request.getRequestURL().toString(); |
|
String key = request.getParameter("target"); |
|
if(StringUtils.isBlank(key)){ |
|
key = getCookieValue(request, "FINE_REDIRECT_PARAM"); |
|
} |
|
if(StringUtils.isBlank(key)){ |
|
return redirectUri; |
|
} |
|
Map<String, String> value = new HashMap<>(); |
|
try { |
|
value = DecisionStatusService.originUrlStatusService().get(key); |
|
if (com.fr.stable.StringUtils.isNotBlank(key) && !value.isEmpty()) { |
|
DecisionStatusService.originUrlStatusService().delete(key); |
|
Map<String, String> finalValue = value; |
|
redirectUri += "?" + value.keySet().stream().map(k -> String.format("%s=%s", k, finalValue.get(k))).collect(Collectors.joining("&")); |
|
} |
|
} catch (Exception e) { |
|
e.printStackTrace(); |
|
} |
|
return redirectUri; |
|
} |
|
|
|
|
|
private boolean exist(String username) { |
|
User user = null; |
|
try { |
|
user = UserService.getInstance().getUserByUserName(username); |
|
} catch (Exception e) { |
|
e.printStackTrace(); |
|
} |
|
return user != null; |
|
} |
|
|
|
private Params getUsername(HttpServletRequest request) throws IllegalAccessException { |
|
String token = getAccessToken(request); |
|
if(StringUtils.isBlank(token)){ |
|
FineLoggerFactory.getLogger().info("token is null"); |
|
return new Params(); |
|
} |
|
return getUsername(request, token); |
|
} |
|
|
|
private Params getUsername(HttpServletRequest request, String accessToken) throws IllegalAccessException { |
|
String url = apiGetUser + "?access_token=" + accessToken; |
|
FineLoggerFactory.getLogger().info("Get user api address is [{}]", url); |
|
try { |
|
String res = HttpToolbox.executeAndParse(HttpRequest.custom().url(url) |
|
.get() |
|
.build()); |
|
FineLoggerFactory.getLogger().info("获取用户信息接口返回内容 ==> {}", res); |
|
JSONObject body = new JSONObject(res); |
|
if (body.getBoolean("success") && body.has("data")) { |
|
body = body.getJSONObject("data"); |
|
if (body.has("account")) { |
|
Params params = new Params(); |
|
params.setRefreshToken(getRefreshToken(request)); |
|
params.setUsername(body.getString("account")); |
|
params.setAccessToken(accessToken); |
|
return params; |
|
} |
|
} |
|
if (body.has("message") && "token不合法".equals(body.getString("message"))) { |
|
FineLoggerFactory.getLogger().info("Access Token [{}] 不合法, 使用Refresh Token[{}]重新获取", accessToken, getRefreshToken(request)); |
|
accessToken = getAccessTokenWithRefreshToken(request); |
|
return getUsername(request, accessToken); |
|
} |
|
throw new IllegalAccessException(); |
|
}catch (IllegalAccessException e){ |
|
throw new IllegalAccessException(); |
|
}catch (Exception e) { |
|
FineLoggerFactory.getLogger().error("获取用户名失败", e); |
|
throw new RuntimeException(e); |
|
} |
|
} |
|
|
|
private String getAccessTokenWithRefreshToken(HttpServletRequest request) throws Exception { |
|
String url = apiRefreshToken + String.format("?refresh_token=%s&client_id=%s&grant_type=refresh_token", getRefreshToken(request), apiClientId); |
|
FineLoggerFactory.getLogger().info("Refresh Token api address is [{}]", url); |
|
String res = HttpToolbox.executeAndParse(HttpRequest.custom().url(url) |
|
.get() |
|
.build()); |
|
FineLoggerFactory.getLogger().info("刷新token接口返回内容 ==> {}", res); |
|
JSONObject body = new JSONObject(res); |
|
if (body.getBoolean("success") && body.has("data")) { |
|
body = body.getJSONObject("data"); |
|
if (body.has("access_token")) { |
|
return body.getString("access_token"); |
|
} |
|
} |
|
throw new IllegalAccessException(); |
|
} |
|
|
|
private String getRefreshToken(HttpServletRequest request) { |
|
return getValueFromRequest(request, "refresh_token"); |
|
} |
|
|
|
private String getAccessToken(HttpServletRequest request) { |
|
return getValueFromRequest(request, "access_token"); |
|
} |
|
|
|
private String getValueFromRequest(HttpServletRequest request, String key) { |
|
try { |
|
String value = request.getParameter(key); |
|
if (StringUtils.isEmpty(value)) { |
|
value = getCookieValue(request, key); |
|
} |
|
if (StringUtils.isEmpty(value)) { |
|
String params = request.getParameter("app"); |
|
params = params.substring(params.indexOf("#") + 1); |
|
Map<String, String> values = Pattern.compile("&").splitAsStream(params).map(e -> e.split("=")).collect(Collectors.toMap(e -> e[0], e -> e[1])); |
|
value = values.get(key); |
|
} |
|
return value; |
|
} catch (Exception e) { |
|
FineLoggerFactory.getLogger().error("Failed to get \"{}\" value from this request, cause by: ", key, e.getMessage()); |
|
FineLoggerFactory.getLogger().error("", e); |
|
} |
|
return ""; |
|
} |
|
|
|
private String getCookieValue(HttpServletRequest request, String key) { |
|
Cookie[] cookies = request.getCookies(); |
|
for (Cookie c : cookies) { |
|
if (StringUtils.equals(c.getName(), key)) { |
|
return c.getValue(); |
|
} |
|
} |
|
return StringUtils.EMPTY; |
|
} |
|
|
|
private void loginFromCode(String code, HttpServletRequest req, HttpServletResponse res) { |
|
FineLoggerFactory.getLogger().info("ssoFilter >>> inside login code param is {}", code); |
|
try { |
|
code = DesECBUtil.decryptDES(code, CODE_KEY); |
|
} catch (Exception e) { |
|
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
|
} |
|
FineLoggerFactory.getLogger().info("ssoFilter >>> inside login code decode is {}", code); |
|
String[] arr = code.split("_"); |
|
loginFromToken(req, res, arr[0]); |
|
} |
|
|
|
private void executeGetAuth(HttpServletRequest req, HttpServletResponse res) { |
|
String uri = WebUtils.getHTTPRequestParameter(req, "redirect_uri"); |
|
String currentUsername = null; |
|
try { |
|
User user= null; |
|
try { |
|
user = UserService.getInstance().getUserByRequest(req); |
|
}catch (Exception e){ |
|
|
|
} |
|
if(user == null){ |
|
user = UserService.getInstance().getUserByRequestCookie(req); |
|
} |
|
currentUsername = user.getUserName(); |
|
String encryptDES = DesECBUtil.encryptDES(String.format("%s_%d", currentUsername, Instant.now().toEpochMilli()), CODE_KEY); |
|
encryptDES = URLEncoder.encode(encryptDES, "UTF-8"); |
|
uri = uri.indexOf("?") == -1 ? uri + "?sign=" + encryptDES : uri + "&sign=" + encryptDES; |
|
res.sendRedirect(uri); |
|
FineLoggerFactory.getLogger().info("ssoFilter >>> inside redirect url is {}", uri); |
|
} catch (Exception e) { |
|
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
|
} |
|
} |
|
|
|
private boolean notExistUser(String username) { |
|
User user = null; |
|
try { |
|
user = UserService.getInstance().getUserByUserName(username); |
|
if (user == null) { |
|
return true; |
|
} |
|
} catch (Exception e) { |
|
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
|
} |
|
return false; |
|
} |
|
|
|
private boolean hasCookie(HttpServletRequest req) { |
|
if (req.getCookies() == null) { |
|
return false; |
|
} |
|
return Stream.of(req.getCookies()).anyMatch(e -> "IAM_SESSION".equalsIgnoreCase(e.getName())); |
|
} |
|
|
|
public LoginRequestInfoBean getLoginInfo(HttpServletRequest req) { |
|
try { |
|
BufferedReader br = req.getReader(); |
|
String str = ""; |
|
String listString = ""; |
|
while ((str = br.readLine()) != null) { |
|
listString += str; |
|
} |
|
JSONObject jsonObject = new JSONObject(listString); |
|
LoginRequestInfoBean info = jsonObject.mapTo(LoginRequestInfoBean.class); |
|
//info.setPassword(TransmissionTool.decrypt(info.isEncrypted(),info.getPassword())); |
|
return info; |
|
} catch (Exception e) { |
|
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
|
} |
|
return null; |
|
|
|
} |
|
|
|
private boolean loginFromToken(HttpServletRequest req, HttpServletResponse res, String username) { |
|
try { |
|
if (StringUtils.isNotEmpty(username)) { |
|
FineLoggerFactory.getLogger().info("current username:" + username); |
|
User user = UserService.getInstance().getUserByUserName(username); |
|
FineLoggerFactory.getLogger().info("get user:" + user); |
|
if (user == null) { |
|
throw new UserNotExistException(); |
|
} |
|
String token = LoginService.getInstance().login(req, res, username); |
|
FineLoggerFactory.getLogger().info("get login token:" + token); |
|
req.setAttribute(DecisionServiceConstants.FINE_AUTH_TOKEN_NAME, token); |
|
FineLoggerFactory.getLogger().info("username:" + username + "login success"); |
|
return true; |
|
} else { |
|
FineLoggerFactory.getLogger().warn("username is null!"); |
|
return false; |
|
} |
|
} catch (Exception e) { |
|
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
|
} |
|
return false; |
|
} |
|
|
|
private void filter(HttpServletRequest req, HttpServletResponse res, FilterChain filterChain) { |
|
try { |
|
filterChain.doFilter(req, res); |
|
} catch (IOException e) { |
|
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
|
} catch (ServletException e) { |
|
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
|
} |
|
} |
|
|
|
private boolean isLogin(HttpServletRequest request) { |
|
String oldToken = TokenResource.COOKIE.getToken(request); |
|
return oldToken != null && checkTokenValid(request, (String) oldToken); |
|
} |
|
|
|
private boolean checkTokenValid(HttpServletRequest req, String token) { |
|
try { |
|
Device device = NetworkHelper.getDevice(req); |
|
LoginService.getInstance().loginStatusValid(token, TerminalHandler.getTerminal(req, device)); |
|
return true; |
|
} catch (Exception ignore) { |
|
} |
|
return false; |
|
} |
|
|
|
public boolean isMobileDevice(HttpServletRequest request) { |
|
String requestHeader = request.getHeader("user-agent"); |
|
String[] deviceArray = new String[]{"android", "iphone", "ios", "windows phone"}; |
|
if (requestHeader == null) { |
|
return false; |
|
} |
|
requestHeader = requestHeader.toLowerCase(); |
|
for (int i = 0; i < deviceArray.length; i++) { |
|
if (requestHeader.contains(deviceArray[i]) && request.getRequestURI().endsWith("/login")) { |
|
FineLoggerFactory.getLogger().info("current request:{} is mobile request!", request.getRequestURI()); |
|
return true; |
|
} |
|
} |
|
return false; |
|
} |
|
}
|
|
|