ç»å¯¹å®å ¨è·¨åç»ä¸åç¹ç»å½ç»åº
åºç¨åºæ¯ï¼å¤ä¸ªç³»ç»ä¸åå±äºä¸ä¸ªç¨æ·ï¼å½ç¨æ·ç»å½äºweb1ç³»ç»ï¼é£ä¹è®¿é®web2ï¼web3. . . . æ¶åï¼ç¨æ·å°±æ é忬¡ç»å½ãå¦ï¼æ·å®ä¸å¤©ç«ï¼ç»åºä¹å¦æ¤ï¼ä¸ä¸ªç³»ç»ç»åºï¼å
¶ä»ç³»ç»çç»å½ä¹éä¹å¤±æï¼è¿å°±æ¯ç»ä¸åç¹ç»å½ç»åºã
è¿éé
ç½®ä¸ä¸ªwebç³»ç»ï¼ä¸ä¸ªç¨æ·ä¸å¿ç³»ç»ä¸ºæ åã
é ç½®hostså®ç°è·¨åï¼
127.0.0.1 ssofront.ljtest.xxxx.com #ç¨æ·ä¸å¿
127.0.0.1 my.kuaiji.com #web1
127.0.0.1 my.zikao.com #web2
127.0.0.1 my.xuelxuew.com #web3
nginx é
ç½®ç¨äºç»ä¸ç»å½é¡µé¢è½¬å
server {
listen 80;
server_name ssofront.ljtest.xxxx.com;
location /ajax/ {
proxy_pass http://ssofront.ljtest.xxxx.com:9092/;
}
location / {
root D:/Java/projects/SSO_Single;
index index.html;
}
}
å
ççææå¾ï¼
ç»ä¸ç»å½é¡µé¢ï¼
ææçwebç³»ç»ç»å½é½éå®åå°ç¨æ·ä¸å¿çç»ä¸ç»å½é¡µé¢
ç»ä¸ç»å½ä¹å访é®åç³»ç»
å½web1ç¹å»ç»å½éå®åå°ç¨æ·ä¸å¿ç»ä¸ç»å½ä¹åï¼å访é®web2ï¼web3ç³»ç»é½å·²ç»æ¯ç»å½ç¶æäºã
è½å¤å®ç°è¿ç§ææå°±è¯´æç¨æ·ä¸å¿ï¼3个webç³»ç»é½åå«å¨èªå·±çåå䏿åçætokenæ¾å°åèªçcookieä¸äºï¼èä¸4个系ç»é½æ¯è·¨åçï¼æä»¥cookieå¨è¿å个系ç»é´æ¯ä¸å¯å
±äº«çï¼æä»¥å·²ç»è¾¾å°è·¨åç»ä¸ç»å½äºã
å¦ä½å®ç°çï¼ï¼æä»¬å
ççæµç¨å¾
åä½çå®å¦æç宿µç¨å¾è¿ä¸æ¯å¾æ¸
æ°ï¼ä¸å¬æåæï¼
å½æä»¬ç¬¬ä¸æ¬¡è®¿é®web1ç³»ç»æ¶ï¼æªç»å½ç¶æï¼å
¶ä»webç³»ç»ä¹æªç»å½è¿ï¼ï¼æ¤æ¶ç»è¿è¿æ»¤å¨ï¼tokenï¼actionå½ç¶ä¸ºnullï¼å°±ä¼æ¥æ¾cookieæ¯å¦åå¨tokenï¼ä¸è¿æ¯å¦åå¾é½æè¿ä¸ªtokenæ¿å°ç¨æ·ä¸å¿å»æ ¡éªï¼ç¬¬ä¸æ¬¡è¯å®æ¿ä¸å°ï¼æä»¥æ ¡éªå¤±è´¥ï¼efftokenæætoken为空ï¼éå®åå°ç¨æ·ä¸å¿ï¼éå®åç±æµè§å¨éæ°ååºå¯ä»¥è·åå°ç¨æ·ä¸å¿çcookieï¼è·åcookieä¸çtokenï¼tokenå»å°SSOæ ¡éªæ¯å¦å¤±æï¼ç¬¬ä¸æ¬¡è®¿é®æä»¥token为空失æï¼è¿åtokenï¼éå®ååweb1ç³»ç»ï¼æ¤æ¶å¾å¸¦ä¸åæ°ï¼è¿åçtoken å action=callback(ç¨ä»¥æ è¯æ¯ç¨æ·ä¸å¿éå®å忥çï¼é¿å
夿¬¡éå®å)ï¼ï¼å°è¿é就宿äºä¸æ¬¡è¯¢é®ï¼åå¦ä¸ç´æªç»å½ï¼æ¯æ¬¡è®¿é®web1ç³»ç»é½ä¼å»ç¨æ·ä¸å¿è¯¢é®æ¯å¦æå«çç³»ç»ç»å½è¿åï¼æå°±è¿åæætokenæ¾å
¥web1ç³»ç»çsessionåcookieä¸ï¼é£ä¹ä¸æ¬¡è®¿é®å°±æ¿çè¿ä¸ªtokenå»ç¨æ·ä¸å¿æ ¡éªå¤ææ¯å¦å¤±æã彿们å»å°ç¨æ·ä¸å¿ç»å½äºçætokenï¼token伿¾å
¥ç¨æ·ä¸å¿çcookieä¸ï¼ç¶åéå®ååweb1ç³»ç»ï¼ç»è¿è¿æ»¤å¨æ¶æ§è¡ä¸è¿°æ¥éª¤ä¾¿å¯ä»¥æ¿å°ç¨æ·ä¸å¿çæætokenãå
¶ä¸ä»»ä½ä¸ä¸ªç³»ç»ç»åºé½ä¼è°ç¨ç¨æ·ä¸å¿åç¹ç»åºï¼æ¤æ¶token失æï¼å
¶ä»ç³»ç»åæ¬¡è®¿é®æ¶å°±ä¼åæ¬¡è¯¢é®æ¯å¦å¤±æï¼å¤±ææ¸
空cookieï¼è¿æ ·å°±å®æç»ä¸ç»åºå¦ãå
¶ä»ç³»ç»åç乿¯å¦æ¤ã
è¿ä¹è¿åå¨ä¸ä¸ªå°é®é¢å°±æ¯å½ä»ç¨æ·ä¸å¿è¯¢é®åç°æ²¡æç»å½è¿ï¼å¸¦åæ°éå®ååweb1ç³»ç»ï¼æµè§å¨ä¸çurlä¼å ä¸åæ° ?token=&action=callbackï¼å½æä»¬åªæ¯å·æ°é¡µé¢æ²¡æå
¶ä»æä½ï¼æ¤æ¶è¿æ»¤å¨ä¸actionå¼ä¸ºcallbackä¼è·³è¿å°ç¨æ·ä¸å¿ç询é®ï¼ètokenæ¯å¤±æçæªç»å½ç¶æï¼æä»¥çç¹å»é¡µé¢å·æ°ï¼è¿ä¸ªé®é¢å¤§å®¶å¦ææ³ç好çè§£å³åæ³å¯ä»¥åè¯æä¸ä¸ã
主è¦ä»£ç ï¼
webç³»ç»ï¼
Login.java
@RequestMapping("/login")
public void login(HttpServletRequest request, HttpServletResponse response){
try {
//è·åä¸ä¸ä¸ªURLå°å
String previousUrl = request.getHeader("Referer").toString();
response.sendRedirect(LOGIN_URL+previousUrl);
}catch (IOException e) {
e.printStackTrace();
}
}
ç»ä¸ç»å½è¿æ»¤å¨
public class UnifiedLoginFilter extends OncePerRequestFilter {
@Value("${tokenExpired.url}")
private String TOKENEXPIRED_URL;
@Value("${userCenterToken.url}")
private String USERCENTERTOKEN_URL;
private final static String ACTION_NAME = "callback";
@Autowired
private UserService userService;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String action = ServletRequestUtils.getStringParameter(request, "action", null);
HttpSession session = request.getSession();
String currentUrl = request.getRequestURL().toString();
//è·åç¨æ·ä¸å¿æætoken
String effectiveToken = null;
String currentToken = null;
boolean doFilter = true;
if(ACTION_NAME.equals(action)) {
effectiveToken = ServletRequestUtils.getStringParameter(request, "token", null);
} else {
currentToken = (String) session.getAttribute(SystemConfig.SESSION_TOKEN_KEY);
Cookie[] cookies = request.getCookies();
if (StringUtils.isBlank(currentToken) && cookies != null) {
for (int i = 0; i < cookies.length; i++) {
Cookie cookie = cookies[i];
if (cookie != null && SystemConfig.COOKIE_TOKEN_NAME.equals(cookie.getName())) {
currentToken = cookie.getValue();
break;
}
}
}
String result = HttpUtil.doGet4Json(TOKENEXPIRED_URL+currentToken);
if(StringUtils.isNotBlank(result)) {
JSONObject object = JSONObject.parseObject(result);
effectiveToken = object.getString("data");
if(StringUtils.isBlank(effectiveToken)) {
doFilter = false;
response.sendRedirect(USERCENTERTOKEN_URL+currentUrl);
}
}
}
if(doFilter) {
//ç¨æ·ä¸å¿tokenææ
if(StringUtils.isNotBlank(effectiveToken)) {
if(effectiveToken.equals(currentToken)) {
//å½åç³»ç»tokenææï¼ætokenåå
¥session
session.setAttribute(SystemConfig.SESSION_TOKEN_KEY, effectiveToken);
} else {
//å½åç³»ç»token失æï¼æ´æ°token
setCookie(effectiveToken, request, response);
}
}
//ç¨æ·ä¸å¿token失æ
else {
removeCookie(request, response);
}
//éå®å廿urlå°ååæ°
if(ACTION_NAME.equals(action) && StringUtils.isNotBlank(effectiveToken)) {
response.sendRedirect(currentUrl);
} else {
filterChain.doFilter(request, response);
}
}
}
}
è¿æ»¤å¨é ç½®web.xml
<!-- ç»ä¸ç»å½è¿æ»¤ -->
<filter>
<filter-name>unifiedLoginFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>unifiedLoginFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
使ç¨DelegatingFilterProxy代çè¿æ»¤å¨ï¼å¯ä»¥è®©Spring管ç被代ççè¿æ»¤å¨ï¼è¿æ ·å°±å¯ä»¥å¨è¿æ»¤å¨ä¸è®¿é®Spring容å¨ä¸çbeanï¼å±æ§çã
ç¨æ·ä¸å¿ï¼
tokenæ ¡éª UserInfo.java
@ApiOperation(value = "éå®åè·åç¨æ·ä¸å¿Token")
@ApiImplicitParam(name = "redirectUrl", value = "åè°å°å", required = true, dataType = "String", paramType = "query")
@RequestMapping(value = "/userCenterToken", method = RequestMethod.GET)
public void userCenterToken(HttpServletRequest request, HttpServletResponse response) {
String redirectUrl = ServletRequestUtils.getStringParameter(request, "redirectUrl", null);
String schoolId = this.getSchoolId(request);
String token = null;
Cookie[] cookies = request.getCookies();
if(null != cookies) {
for (int i = 0; i < cookies.length; i++) {
Cookie cookie = cookies[i];
if (cookie != null && config.getCookieTokenName().equals(cookie.getName())) {
token = cookie.getValue();
break;
}
}
}
try {
String effectiveToken = getEffectiveToken(token,schoolId);
response.sendRedirect(redirectUrl+"?token="+effectiveToken+"&action=callback");
} catch (Exception e) {
TRACER.error("", e);
e.printStackTrace();
}
}
@ApiOperation(value = "æ ¡éªTokenæ¯å¦å¤±æ")
@ApiImplicitParam(name = "token", value = "ç¨æ· Token", required = true, dataType = "String", paramType = "query")
@RequestMapping(value = "/tokenExpired", method = RequestMethod.GET)
@ResponseBody
public ResponseEntity<WrappedResponse<String>> tokenExpired(HttpServletRequest request, HttpServletResponse response) {
try {
String token = ServletRequestUtils.getStringParameter(request, "token", null);
String schoolId = this.getSchoolId(request);
String effectiveToken = getEffectiveToken(token,schoolId);
return this.success(effectiveToken);
} catch (Throwable t) {
TRACER.error("", t);
return this.fail(TransactionStatus.INTERNAL_SERVER_ERROR);
}
}
private String getEffectiveToken(String token, String schoolId) throws Exception {
String effectiveToken = "";
HashMap<String, Object> map = new HashMap<>(1);
map.put("token", token);
HttpPlainResult result = httpConnManager.invoke(HttpMethod.GET, config.getSsoHost()+"/inner/tokenExpired", map,schoolId);
TRACER.info(result.getResult());
HttpResultDetail<TokenStatus> entry = HttpResultHandler.handle(result, TokenStatus.class);
if (entry.isOK()) {
TokenStatus tokenStatus = entry.getResult();
if (!tokenStatus.getExpired()) {
effectiveToken = token;
}
}
return effectiveToken;
}
ç»ä¸ç»å½ Login.java
HttpPlainResult result = httpConnManager.invoke(HttpMethod.POST, config.getSsoHost() + â/inner/loginâ, map, schoolId);
TRACER.info(result.getResult());
HttpResultDetail entry = HttpResultHandler.handle(result,Token.class);
if(entry.isOK()){
ClientTypeEnum clientTypeEnum = ClientTypeEnum.convertString2ClientType(clientType);
if(clientTypeEnum == ClientTypeEnum.WEB){
String token = entry.getResult().getToken();
Cookie token_cookie = new Cookie(config.getCookieTokenName(),token);
token_cookie.setMaxAge(config.getCookieTokenTimeout());
token_cookie.setDomain(request.getHeader("Host").split(":")[0]);
response.addCookie(token_cookie);
return this.success(redirectUrl,token_cookie);
}else{
return this.success(entry.getResult(), entry.getResponseStatus());
}
}else if(entry.isClientError()){
return this.error(entry.getResponseMessage(), entry.getResponseStatus());
}else if(entry.isServerError()){
return this.fail(entry.getResponseMessage(), entry.getResponseStatus());
}
ç»ä¸ç»åº Logout.java
HttpPlainResult result = httpConnManager.invoke(HttpMethod.POST, config.getSsoHost()+â/inner/logoutâ, map,schoolId);
TRACER.info(result.getResult());
HttpResultDetail entry = HttpResultHandler.handle(result,String.class);
if(entry.isOK()){
Cookie token_cookie = new Cookie(config.getCookieTokenName(),null);
token_cookie.setMaxAge(0);
token_cookie.setDomain(request.getHeader(âHostâ).split(â:â)[0]);
response.addCookie(token_cookie);
return this.success(entry.getResult(), entry.getResponseStatus());
}else if(entry.isClientError()){
return this.error(entry.getResponseMessage(), entry.getResponseStatus());
}else if(entry.isServerError()){
return this.fail(entry.getResponseMessage(), entry.getResponseStatus());
}