package com.zheng.upms.client.shiro.filter; import com.alibaba.fastjson.JSONObject; import com.zheng.common.util.PropertiesFileUtil; import com.zheng.common.util.RedisUtil; import com.zheng.upms.client.shiro.session.UpmsSessionDao; import com.zheng.upms.client.util.RequestParameterUtil; import com.zheng.upms.common.constant.UpmsConstant; import org.apache.commons.lang.StringUtils; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.NameValuePair; import org.apache.http.client.HttpClient; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.message.BasicNameValuePair; import org.apache.http.util.EntityUtils; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.session.Session; import org.apache.shiro.subject.Subject; import org.apache.shiro.web.filter.authc.AuthenticationFilter; import org.apache.shiro.web.util.WebUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import redis.clients.jedis.Jedis; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.net.URLEncoder; import java.util.ArrayList; import java.util.List; /** * 重写authc过滤器 * Created by shuzheng on 2017/3/11. */ public class UpmsAuthenticationFilter extends AuthenticationFilter { private final static Logger _log = LoggerFactory.getLogger(UpmsAuthenticationFilter.class); // 局部会话key private final static String ZHENG_UPMS_CLIENT_SESSION_ID = "zheng-upms-client-session-id"; // 单点同一个code所有局部会话key private final static String ZHENG_UPMS_CLIENT_SESSION_IDS = "zheng-upms-client-session-ids"; @Autowired UpmsSessionDao upmsSessionDao; @Override protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) { Subject subject = getSubject(request, response); Session session = subject.getSession(); // 判断请求类型 String upmsType = PropertiesFileUtil.getInstance("zheng-upms-client").get("upms.type"); session.setAttribute(UpmsConstant.UPMS_TYPE, upmsType); if ("client".equals(upmsType)) { return validateClient(request, response); } if ("server".equals(upmsType)) { return subject.isAuthenticated(); } return false; } @Override protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { StringBuffer sso_server_url = new StringBuffer(PropertiesFileUtil.getInstance("zheng-upms-client").get("sso.server.url")); // server需要登录 String upmsType = PropertiesFileUtil.getInstance("zheng-upms-client").get("upms.type"); if ("server".equals(upmsType)) { WebUtils.toHttp(response).sendRedirect(sso_server_url.append("/sso/login").toString()); return false; } sso_server_url.append("/sso/index").append("?").append("appid").append("=").append(PropertiesFileUtil.getInstance("zheng-upms-client").get("appID")); // 回跳地址 HttpServletRequest httpServletRequest = WebUtils.toHttp(request); StringBuffer backurl = httpServletRequest.getRequestURL(); String queryString = httpServletRequest.getQueryString(); if (StringUtils.isNotBlank(queryString)) { backurl.append("?").append(queryString); } sso_server_url.append("&").append("backurl").append("=").append(URLEncoder.encode(backurl.toString(), "utf-8")); WebUtils.toHttp(response).sendRedirect(sso_server_url.toString()); return false; } /** * 认证中心登录成功带回code * @param request */ private boolean validateClient(ServletRequest request, ServletResponse response) { Subject subject = getSubject(request, response); Session session = subject.getSession(); String sessionId = session.getId().toString(); int timeOut = (int) session.getTimeout() / 1000; // 判断局部会话是否登录 String cacheClientSession = RedisUtil.get(ZHENG_UPMS_CLIENT_SESSION_ID + "_" + session.getId()); if (StringUtils.isNotBlank(cacheClientSession)) { // 更新code有效期 RedisUtil.set(ZHENG_UPMS_CLIENT_SESSION_ID + "_" + sessionId, cacheClientSession, timeOut); Jedis jedis = RedisUtil.getJedis(); jedis.expire(ZHENG_UPMS_CLIENT_SESSION_IDS + "_" + cacheClientSession, timeOut); jedis.close(); // 移除url中的code参数 if (null != request.getParameter("code")) { String backUrl = RequestParameterUtil.getParameterWithOutCode(WebUtils.toHttp(request)); HttpServletResponse httpServletResponse = WebUtils.toHttp(response); try { httpServletResponse.sendRedirect(backUrl.toString()); } catch (IOException e) { _log.error("局部会话已登录,移除code参数跳转出错:", e); } } else { return true; } } // 判断是否有认证中心code String code = request.getParameter("upms_code"); // 已拿到code if (StringUtils.isNotBlank(code)) { // HttpPost去校验code try { StringBuffer sso_server_url = new StringBuffer(PropertiesFileUtil.getInstance("zheng-upms-client").get("sso.server.url")); HttpClient httpclient = new DefaultHttpClient(); HttpPost httpPost = new HttpPost(sso_server_url.toString() + "/sso/code"); List<NameValuePair> nameValuePairs = new ArrayList<>(); nameValuePairs.add(new BasicNameValuePair("code", code)); httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs)); HttpResponse httpResponse = httpclient.execute(httpPost); if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { HttpEntity httpEntity = httpResponse.getEntity(); JSONObject result = JSONObject.parseObject(EntityUtils.toString(httpEntity)); if (1 == result.getIntValue("code") && result.getString("data").equals(code)) { // code校验正确,创建局部会话 RedisUtil.set(ZHENG_UPMS_CLIENT_SESSION_ID + "_" + sessionId, code, timeOut); // 保存code对应的局部会话sessionId,方便退出操作 RedisUtil.sadd(ZHENG_UPMS_CLIENT_SESSION_IDS + "_" + code, sessionId, timeOut); _log.debug("当前code={},对应的注册系统个数:{}个", code, RedisUtil.getJedis().scard(ZHENG_UPMS_CLIENT_SESSION_IDS + "_" + code)); // 移除url中的token参数 String backUrl = RequestParameterUtil.getParameterWithOutCode(WebUtils.toHttp(request)); // 返回请求资源 try { // client无密认证 String username = request.getParameter("upms_username"); subject.login(new UsernamePasswordToken(username, "")); HttpServletResponse httpServletResponse = WebUtils.toHttp(response); httpServletResponse.sendRedirect(backUrl.toString()); return true; } catch (IOException e) { _log.error("已拿到code,移除code参数跳转出错:", e); } } else { _log.warn(result.getString("data")); } } } catch (IOException e) { _log.error("验证token失败:", e); } } return false; } }