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.
203 lines
7.9 KiB
203 lines
7.9 KiB
package com.fr.plugin.sunac.sso; |
|
|
|
import com.fr.base.Base64; |
|
import com.fr.decision.fun.impl.AbstractGlobalRequestFilterProvider; |
|
import com.fr.decision.webservice.bean.user.UserBean; |
|
import com.fr.decision.webservice.v10.user.UserService; |
|
import com.fr.general.PropertiesUtils; |
|
import com.fr.general.http.HttpToolbox; |
|
import com.fr.intelli.record.Focus; |
|
import com.fr.intelli.record.Original; |
|
import com.fr.json.JSONObject; |
|
import com.fr.log.FineLoggerFactory; |
|
import com.fr.plugin.context.PluginContexts; |
|
import com.fr.plugin.transform.FunctionRecorder; |
|
import com.fr.security.encryption.transmission.TransmissionEncryptors; |
|
import com.fr.stable.StringUtils; |
|
import com.fr.stable.fun.Authorize; |
|
|
|
import javax.servlet.FilterChain; |
|
import javax.servlet.http.HttpServletRequest; |
|
import javax.servlet.http.HttpServletResponse; |
|
import java.io.IOException; |
|
import java.nio.charset.StandardCharsets; |
|
import java.util.*; |
|
import java.util.stream.Stream; |
|
|
|
import static com.fr.plugin.sunac.sso.CommonUtils.*; |
|
|
|
/** |
|
* @author fr.open |
|
* @since 2021/8/10 |
|
*/ |
|
@FunctionRecorder |
|
@Authorize(callSignKey = PluginConstants.PLUGIN_ID) |
|
public class SsoFilter extends AbstractGlobalRequestFilterProvider { |
|
|
|
private static String[] NOT_FILTER = { |
|
"/decision/file", |
|
"/decision/resources", |
|
"/system", |
|
"/materials.min.js.map", |
|
"/remote", |
|
"/login", |
|
"/url/mobile", |
|
"/pushResult", |
|
"/login/config", |
|
"/css/" |
|
}; |
|
|
|
private final String apiAuthorize; |
|
|
|
private final String apiClientId; |
|
|
|
private final String apiRedirectURI; |
|
|
|
private final String apiGetToken; |
|
|
|
private final String apiClientSecret; |
|
|
|
private final String apiGetUser; |
|
|
|
private final String defaultPassword; |
|
|
|
public SsoFilter() { |
|
Properties props = PropertiesUtils.getProperties("sunac"); |
|
apiAuthorize = getProperty(props, "api.authorize", true); |
|
apiClientId = getProperty(props, "api.client_id", true); |
|
apiRedirectURI = getProperty(props, "api.redirect_uri", true); |
|
apiGetToken = getProperty(props, "api.get-token", true); |
|
apiClientSecret = getProperty(props, "api.client_secret", true); |
|
apiGetUser = getProperty(props, "api.get-user", true); |
|
defaultPassword = getProperty(props, "new.user.password", "MfMy8c96Aqyqzt6F", true); |
|
} |
|
|
|
@Override |
|
@Focus(id = PluginConstants.PLUGIN_ID, text = "融创西南单点登录", source = Original.PLUGIN) |
|
public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) { |
|
if (!PluginContexts.currentContext().isAvailable() || isAccept(request)) { |
|
next(request, response, chain); |
|
return; |
|
} |
|
try { |
|
if (StringUtils.isBlank(apiAuthorize) |
|
|| StringUtils.isBlank(apiClientId) |
|
|| StringUtils.isBlank(apiRedirectURI) |
|
|| StringUtils.isBlank(apiClientSecret) |
|
|| StringUtils.isBlank(apiGetToken) |
|
|| StringUtils.isBlank(apiGetUser)) { |
|
throw new RuntimeException("Property [api.authorize] " + |
|
"or [api.client_id] " + |
|
"or [api.redirect_uri] " + |
|
"or [api.client_secret]" + |
|
"or [api.get-token]" + |
|
"or [api.get-user]" + |
|
"hasn't a valid value"); |
|
} |
|
String code = request.getParameter("code"); |
|
if (StringUtils.isBlank(code)) { |
|
jumpAuthorize(request, response); |
|
return; |
|
} |
|
String username = getUsername(getToken(code)); |
|
try { |
|
getUser(username); |
|
} catch (Exception e) { |
|
UserBean bean = new UserBean(); |
|
bean.setEnable(true); |
|
bean.setRealName(username); |
|
bean.setUsername(username.toLowerCase()); |
|
bean.setPassword(TransmissionEncryptors.getInstance().encrypt(defaultPassword)); |
|
UserService.getInstance().addUser(bean); |
|
} |
|
login(username, request, response); |
|
String state = request.getParameter("state"); |
|
if (StringUtils.isNotBlank(state)) { |
|
String accessURL = getCachedParam(state, "accessURL"); |
|
if (StringUtils.isNotBlank(accessURL)) { |
|
response.sendRedirect(accessURL); |
|
return; |
|
} |
|
} |
|
next(request, response, chain); |
|
} catch (Exception e) { |
|
FineLoggerFactory.getLogger().error("SSO processing failed, Cause by: ", e); |
|
setError(response, e.getMessage()); |
|
} |
|
} |
|
|
|
private String getUsername(String token) throws IOException { |
|
Map<String, String> headers = new HashMap<>(); |
|
headers.put("Authorization", token); |
|
headers.put("Content-Type", "application/x-www-form-urlencoded"); |
|
String res = HttpToolbox.get(apiGetUser, Collections.emptyMap(), headers); |
|
FineLoggerFactory.getLogger().info("获取用户信息接口返回内容: \"{}\"", res); |
|
JSONObject body = new JSONObject(res); |
|
if (body.has("uid")) { |
|
String username = body.getString("uid"); |
|
FineLoggerFactory.getLogger().info("获取到的用户名为: \"{}\"", username); |
|
return username; |
|
} |
|
throw new RuntimeException("用户信息获取失败, 详见接口返回内容"); |
|
} |
|
|
|
private void jumpAuthorize(HttpServletRequest request, HttpServletResponse response) throws IOException { |
|
String state = UUID.randomUUID().toString(); |
|
String accessURL = request.getRequestURI(); |
|
if (StringUtils.isNotBlank(request.getQueryString())) { |
|
accessURL += "?" + request.getQueryString(); |
|
} |
|
Map<String, String> params = new HashMap<>(); |
|
params.put("accessURL", accessURL); |
|
cacheParams(state, params); |
|
String pattern = "%s?client_id=%s&redirect_uri=%s&response_type=code&scope=UserProfile.me&state=%s"; |
|
pattern = String.format(pattern, apiAuthorize, apiClientId, apiRedirectURI, state); |
|
response.sendRedirect(pattern); |
|
} |
|
|
|
private String getToken(String code) throws IOException { |
|
Map<String, Object> params = new HashMap<>(); |
|
params.put("redirect_uri", apiRedirectURI); |
|
params.put("code", code); |
|
params.put("grant_type", "authorization_code"); |
|
Map<String, String> headers = new HashMap<>(); |
|
headers.put("Content-Type", "application/x-www-form-urlencoded"); |
|
headers.put("Authorization", "Basic " + Base64.encode((apiClientId + ":" + apiClientSecret).getBytes(StandardCharsets.UTF_8))); |
|
String res = HttpToolbox.post(apiGetToken, params, headers); |
|
FineLoggerFactory.getLogger().info("获取Token接口返回内容: \"{}\"", res); |
|
JSONObject body = new JSONObject(res); |
|
if (body.has("access_token")) { |
|
String token = body.getString("access_token"); |
|
FineLoggerFactory.getLogger().info("获取到的token值为: \"{}\"", token); |
|
return token; |
|
} |
|
throw new RuntimeException("获取token失败, 详见接口返回内容"); |
|
} |
|
|
|
public boolean isAccept(HttpServletRequest request) { |
|
// 已登录 |
|
if (isLogin(request)) { |
|
return true; |
|
} |
|
// 手机端请求 |
|
if (isMobileDevice(request)) { |
|
return true; |
|
} |
|
// 默认放行地址 |
|
String url = request.getRequestURL().toString(); |
|
if (url.endsWith(".css") || url.endsWith(".js") || url.endsWith(".jsp")) { |
|
return true; |
|
} |
|
return Stream.of(NOT_FILTER).anyMatch(url::contains); |
|
} |
|
|
|
@Override |
|
public String filterName() { |
|
return "sso"; |
|
} |
|
|
|
@Override |
|
public String[] urlPatterns() { |
|
return new String[]{"/*"}; |
|
} |
|
}
|
|
|