package com.github.ebnew.ki4so.core.service;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;
import com.github.ebnew.ki4so.common.utils.StringUtils;
import com.github.ebnew.ki4so.core.app.App;
import com.github.ebnew.ki4so.core.app.AppService;
import com.github.ebnew.ki4so.core.authentication.status.UserLoggedStatus;
import com.github.ebnew.ki4so.core.authentication.status.UserLoggedStatusStore;
import com.github.ebnew.ki4so.web.utils.WebConstants;
/**
* 统一登出服务
* @author ywbrj042
*/
public class LogoutAppServiceImpl implements LogoutAppService {
private static Logger logger = Logger.getLogger(LogoutAppServiceImpl.class);
private static CloseableHttpClient httpClient = HttpClients.createDefault();
/**
* 默认请求失败重试次数。
*/
private static final int RETRY_TIMES = 3;
private AppService appService;
private UserLoggedStatusStore userLoggedStatusStore;
public void setUserLoggedStatusStore(UserLoggedStatusStore userLoggedStatusStore) {
this.userLoggedStatusStore = userLoggedStatusStore;
}
public void setAppService(AppService appService) {
this.appService = appService;
}
/**
* 该方法主要是退出app
*/
@Override
public void logoutApp(final String userId, final String service) {
if(StringUtils.isEmpty(userId)){
return;
}
//servie对应的app
App app = null;
//先查找service对应的应用登出地址。
if(!StringUtils.isEmpty(service)){
app = appService.findAppByHost(service);
if(app!=null){
String logoutUrl = app.getLogoutUrl();
//登出service对应的应用。
requestLogoutUrl(logoutUrl, userId);
}
}
this.logoutAppsExcludeServiceApp(userId, app);
}
/**
* 请求登出URL地址。若登出失败则会自动重试
*/
protected void requestLogoutUrl(String url, String userId) {
if(StringUtils.isEmpty(url)){
return;
}
for(int i=0; i<RETRY_TIMES; i++){
List<NameValuePair> nvps = new ArrayList<NameValuePair>();
nvps.add(new BasicNameValuePair(WebConstants.USER_ID_PARAM_NAME, userId));
try {
String content = requestUrl(url, nvps);
//当登出成功,则不再重试。
if(!StringUtils.isEmpty(content)){
logger.info("logout sucess ,the url is "+url);
break;
}
logger.info(content);
} catch (ClientProtocolException e) {
logger.warn("request the url error", e);
} catch (IOException e) {
logger.warn("request the url error", e);
}
}
}
/**
* 请求某个URL,带着参数列表。
* @param url
* @param nameValuePairs
* @return
* @throws ClientProtocolException
* @throws IOException
*/
protected String requestUrl(String url, List<NameValuePair> nameValuePairs) throws ClientProtocolException, IOException {
HttpPost httpPost = new HttpPost(url);
if(nameValuePairs!=null && nameValuePairs.size()>0){
httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
}
CloseableHttpResponse response = httpClient.execute(httpPost);
try {
if (response.getStatusLine().getStatusCode() == 200) {
HttpEntity entity = response.getEntity();
String content = EntityUtils.toString(entity);
EntityUtils.consume(entity);
return content;
}
else{
logger.warn("request the url: "+url+" , but return the status code is "+response.getStatusLine().getStatusCode());
return null;
}
}
finally{
response.close();
}
}
/**
* 异步登出用户ID userId登录过的所有应用,排除app.
* @param userId 用户ID.
* @param serviceApp 要排除的app,该app已经登出过。
*/
protected void logoutAppsExcludeServiceApp(String userId, App serviceApp) {
List<UserLoggedStatus> list = this.userLoggedStatusStore.findUserLoggedStatus(userId);
//批量查询对应的应用信息。
if(list!=null&& list.size()>0){
for(UserLoggedStatus status:list){
App app = appService.findAppById(status.getAppId());
if(app!=null){
//若该app已经登出过,则跳过。
if(serviceApp!=null && serviceApp.getAppId().equals(app.getAppId())){
continue;
}
String logoutUrl = app.getLogoutUrl();
//登出service对应的应用。
requestLogoutUrl(logoutUrl, userId);
}
}
}
}
}