|
|
|
@ -0,0 +1,204 @@
|
|
|
|
|
package com.fr.plugin.ctfo.sso; |
|
|
|
|
|
|
|
|
|
import com.fr.base.PropertiesUtils; |
|
|
|
|
import com.fr.common.util.Assert; |
|
|
|
|
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.utils.DecisionServiceConstants; |
|
|
|
|
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.HttpToolbox; |
|
|
|
|
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 javax.servlet.FilterChain; |
|
|
|
|
import javax.servlet.http.HttpServletRequest; |
|
|
|
|
import javax.servlet.http.HttpServletResponse; |
|
|
|
|
import java.io.IOException; |
|
|
|
|
import java.net.URLEncoder; |
|
|
|
|
import java.time.Instant; |
|
|
|
|
import java.util.Collections; |
|
|
|
|
import java.util.Properties; |
|
|
|
|
import java.util.stream.Stream; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* @author fr.open |
|
|
|
|
* @since 2021/5/25 |
|
|
|
|
*/ |
|
|
|
|
@FunctionRecorder |
|
|
|
|
public class Oauth2Filter extends AbstractGlobalRequestFilterProvider { |
|
|
|
|
|
|
|
|
|
private static final String[] NOT_FILTER = { |
|
|
|
|
"/decision/file", |
|
|
|
|
"/decision/resources", |
|
|
|
|
"/system", |
|
|
|
|
"/materials.min.js.map", |
|
|
|
|
"/remote", |
|
|
|
|
"/login", |
|
|
|
|
"/login/config", |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
private final String apiAuthorize; |
|
|
|
|
|
|
|
|
|
private final String apiAppKey; |
|
|
|
|
|
|
|
|
|
private final String apiAppSecret; |
|
|
|
|
|
|
|
|
|
private final String apiGetToken; |
|
|
|
|
|
|
|
|
|
private final String apiGetUser; |
|
|
|
|
|
|
|
|
|
public Oauth2Filter() { |
|
|
|
|
Properties props = PropertiesUtils.getProperties("xplatform"); |
|
|
|
|
apiAuthorize = getValue(props, "api.authorize"); |
|
|
|
|
apiAppKey = getValue(props, "api.app-key"); |
|
|
|
|
apiAppSecret = getValue(props, "api.app-secret"); |
|
|
|
|
apiGetToken = getValue(props, "api.get-token"); |
|
|
|
|
apiGetUser = getValue(props, "api.get-user"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private String getValue(Properties props, String key) { |
|
|
|
|
String value = props.getProperty(key); |
|
|
|
|
Assert.hasText(value, "配置项[" + key + "]不能为空"); |
|
|
|
|
return value; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
public String filterName() { |
|
|
|
|
return "ctfoOauth2"; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
public String[] urlPatterns() { |
|
|
|
|
return new String[]{"/*"}; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) { |
|
|
|
|
final String url = request.getRequestURL().toString(); |
|
|
|
|
FineLoggerFactory.getLogger().info("sso >> URL of this request => {}", url); |
|
|
|
|
try { |
|
|
|
|
if (isLogin(request) || Stream.of(NOT_FILTER).anyMatch(url::contains)) { |
|
|
|
|
FineLoggerFactory.getLogger().info("sso >> 已登录或默认可放行的请求地址"); |
|
|
|
|
chain.doFilter(request, response); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
String code = request.getParameter("code"); |
|
|
|
|
if (StringUtils.isBlank(code)) { |
|
|
|
|
FineLoggerFactory.getLogger().info("sso >> Parameter['code'] 值为空, 跳转到登录页"); |
|
|
|
|
toAuthorize(request, response); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
FineLoggerFactory.getLogger().info("sso >> Parameter['code'] => [{}]", code); |
|
|
|
|
String token; |
|
|
|
|
try { |
|
|
|
|
token = getAccessToken(request, code); |
|
|
|
|
} catch (Exception e) { |
|
|
|
|
FineLoggerFactory.getLogger().error("sso >> 获取access token失败", e); |
|
|
|
|
chain.doFilter(request, response); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
FineLoggerFactory.getLogger().info("sso >> AccessToken => [{}]", token); |
|
|
|
|
String username; |
|
|
|
|
try { |
|
|
|
|
username = getUsername(token); |
|
|
|
|
} catch (Exception e) { |
|
|
|
|
FineLoggerFactory.getLogger().error("sso >> 获取用户名失败", e); |
|
|
|
|
chain.doFilter(request, response); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
FineLoggerFactory.getLogger().info("sso >> username => [{}]", token); |
|
|
|
|
login(username, request, response); |
|
|
|
|
chain.doFilter(request, response); |
|
|
|
|
} catch (Exception e) { |
|
|
|
|
throw new RuntimeException(e); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private void toAuthorize(HttpServletRequest request, HttpServletResponse response) throws IOException { |
|
|
|
|
String urlPattern = "%s?response_type=code&client_id=%s&redirect_uri=%s&oauth_timestamp=%s"; |
|
|
|
|
String rURI = request.getRequestURL().toString(); |
|
|
|
|
// if (request.getQueryString() != null) {
|
|
|
|
|
// rURI += "?" + request.getQueryString();
|
|
|
|
|
// }
|
|
|
|
|
rURI = URLEncoder.encode(rURI, "utf-8"); |
|
|
|
|
String url = String.format(urlPattern, apiAuthorize, apiAppKey, rURI, Instant.now().toEpochMilli()); |
|
|
|
|
FineLoggerFactory.getLogger().info("sso >> 登录认证地址 => [{}]", url); |
|
|
|
|
response.sendRedirect(url); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private String getAccessToken(HttpServletRequest request, String code) throws IOException, IllegalAccessException { |
|
|
|
|
String api = "%s?grant_type=authorization_code&oauth_timestamp=%s&client_id=%s&client_secret=%s&code=%s&redirect_uri=%s"; |
|
|
|
|
String rURI = request.getRequestURL().toString(); |
|
|
|
|
rURI = URLEncoder.encode(rURI, "utf-8"); |
|
|
|
|
// if (request.getQueryString() != null) {
|
|
|
|
|
// rURI += "?" + request.getQueryString();
|
|
|
|
|
// }
|
|
|
|
|
api = String.format(api, apiGetToken, Instant.now().toEpochMilli(), apiAppKey, apiAppSecret, code, rURI); |
|
|
|
|
FineLoggerFactory.getLogger().info("sso >> CODE换取AccessToken的接口地址 => [{}]", api); |
|
|
|
|
String response = HttpToolbox.post(api, Collections.emptyMap()); |
|
|
|
|
FineLoggerFactory.getLogger().info("sso >> CODE换取AccessToken的接口返回内容 => [{}]", response); |
|
|
|
|
JSONObject res = new JSONObject(response); |
|
|
|
|
if (res.has("access_token") && StringUtils.isNotBlank(res.getString("access_token"))) { |
|
|
|
|
return res.getString("access_token"); |
|
|
|
|
} |
|
|
|
|
throw new IllegalAccessException(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private String getUsername(String token) throws IOException, IllegalAccessException { |
|
|
|
|
String api = String.format("%s?access_token=%s", apiGetUser, token); |
|
|
|
|
FineLoggerFactory.getLogger().info("sso >> 获取用户信息接口地址 => [{}]", api); |
|
|
|
|
String response = HttpToolbox.get(api); |
|
|
|
|
FineLoggerFactory.getLogger().info("sso >> 获取用户信息接口地址返回内容 => [{}]", response); |
|
|
|
|
JSONObject res = new JSONObject(response); |
|
|
|
|
if (res.has("attributes")) { |
|
|
|
|
JSONObject attrs = res.getJSONObject("attributes"); |
|
|
|
|
if (attrs.has("account_no") && StringUtils.isNotBlank(attrs.getString("account_no"))) { |
|
|
|
|
return attrs.getString("account_no"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
throw new IllegalAccessException(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private void login(String username, HttpServletRequest request, HttpServletResponse response) { |
|
|
|
|
try { |
|
|
|
|
User user = UserService.getInstance().getUserByUserName(username); |
|
|
|
|
if (user == null) { |
|
|
|
|
FineLoggerFactory.getLogger().error("sso >> User \"{}\" does not exist", username); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
FineLoggerFactory.getLogger().info("sso >> Getted user: {}", user); |
|
|
|
|
String token = LoginService.getInstance().login(request, response, username); |
|
|
|
|
FineLoggerFactory.getLogger().info("sso >> Getted login token: {}", token); |
|
|
|
|
request.setAttribute(DecisionServiceConstants.FINE_AUTH_TOKEN_NAME, token); |
|
|
|
|
FineLoggerFactory.getLogger().info("sso >> User[{}] login successfully", username); |
|
|
|
|
} catch (Exception e) { |
|
|
|
|
FineLoggerFactory.getLogger().error("sso >> Failed to login with[" + username + "]", 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; |
|
|
|
|
} |
|
|
|
|
} |