jfinal与kisso跨域单点登陆
来源:互联网 发布:怎样查店铺直通车数据 编辑:程序博客网 时间:2024/04/28 12:08
1. 引言
之前介绍了kisso与jfinal的简单使用,但是单单这种方式满足不了一些需求,举个例子,一个系统的中分别有很多的子系统,这样的情况下我们做单点登陆,就面临着一个问题,在不同的子系统中IP地址不一样,域名不一样,相对的用户登陆自后所对应的cookie就不能带到其他系统上去。相当于之前登陆的是无效的,又要重新进行登陆。这就所谓的跨域问题。
2. 流程
kisso解决跨域的流程如图(官方的图)
大致意思是,用户登陆,访问sso服务器,进行账户密码校验,如果登陆成功则返回一个token给用户返回的形式为cookie。然后 用户又去访问其他的子系统,这是由于域名不一样,先前的登陆成功的token就不会被带过去,子系统发现用户没有token,就跳转sso系统询问用户是否登陆,这时跳转就会带上我们之前的token了,sso系统拿到用户的token就代表着用户登陆过。然后返回一个应答给子系统也就是这里的my了。子系统收到sso的应答信息,判断用户是否登陆过,如果登陆过就重新生成一个token,注意这里的token跟先前的token是不会冲突的,因为domain不一样。最后就返回给用户想访问的页面。
3. 具体过程
先配置sso系统。
1.1首先是配置文件
################ SSOConfig file #################sso.secretkey=h2wmABdfM7i3K801mysso.cookie.name=uidsso.cookie.domain=.test.com# Default RC4 , You can choose [ DES , AES , BLOWFISH , RC2 , RC4 ]#sso.encrypt.algorithm=BLOWFISHsso.login.url=http://sso.test.com:8080/login# crossdomain secretkeysso.authcookie.secretkey=Lg8V51188n0709i5l81# userConfig definedsso.defined.my_public_key=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDKeDkRea/pgX2K6V/eOCQ8kImiqH+QkONx+ubVkvME9mr0I4lElNr8Hl1Q2zEQ+zz4zgDyOWoiCBxSwagBPTate15aMs+uplJL74ScW5gduBYcoQfHURC/ORCFGoa5Y6049p1lhow31yKkKGNTYQYupdlR4HFbqESOPFMwFnG0gQIDAQABsso.defined.sso_private_key=MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAINmYBmAlxBXReME6T8IHadH4BdfJUx1wSsuDPkthv+D8Cvu2IeFiUaTr3+aUi0Oe8fF5X+3uJsSrC9CeUOIzoGxhb/0cHNhaIXngPuHF3YxRao2K3bfalLleWbO6usWaqFKiatHQookegDcciwgYn8BP3HMNv3cao+0Obpi3bh/AgMBAAECgYBPbtn1ULkBleCXpmZiRkO21kpvloLzv9OwiLwq/gy39kiAJnkbI+yij7DuEJpQxoqpb8aW+LdOd3FDeInZ+5/qAW5wdMgvABIINxpsQvED9RWb8NvL7Hqvv/ByMFONhyxdbzRDEVcR6SG7pGTJ1NY4TvfUmLDJrXa5N1LZ5lwZoQJBAN2bUnqVwWaQA5V7ZCEPYKAu6rQj0W6fKzcM84Q7dFskF7ZN8lK2zDtiyH9HTYCPtg51rdtIjZ6O2TVz8pDfp/cCQQCXywmR8HxLWhpvQ28e0LbqPMZrP2FBPo9Fe/UneIOtFhi1bC78xvY3b00a7qHSca8UuWGdzI0FPPhaRsLjfaG5AkEAi1gUR8KMxqn9puvcrTEXKAH4UOdI1I8/RDFfmiEsa/bI9jgTDFGnIBxgSDAUmqdC6dqzRHRdoHrgN809lD0eRwJAN2XEUlzAIAf8ScsEjOyDNS2FBLMW3WblhuhcalFTTSIZVmzrIRnD1itqqn+Y02LmENwvQhXbCaRcxyW4DqpVEQJABMSyhR1YzeXHmRVs3k8+eQOZPitUKsArs/tSbt5VB9Ym98anq7VNIXrFDmKsEQTuoIamva94yF7vu1HcrR/LiQ==
因为kisso的默认的加密机制是RC4,这个加密方式是可以更改的。sso系统必须的保存各个系统的公钥,以及自己的私钥,为什么呢?因为涉及到数据的验证以及数据的加密。这不是废话么,好了,子系统向sso询问用户是否登陆的时候会发送一些加密信息,然后sso系统拿到这些信息后就要用子系统的公钥来验证是否是子系统所发送的,然后在向子系统发送应答信息,当然这也是加密的,子系统拿到以后在进行验证。从而保证了一定的安全性。上面的篇日志文件还有一点需要注意的是sso.authcookie.secretkey这个属性每个系统都要写成一样的,方便加密与解密。
1.2配置jfinal
jfinal的配置如下
package com.withub.demo.config;import com.jfinal.config.*;import com.withub.demo.controller.IndexController;import com.withub.demo.controller.LoginController;import com.withub.demo.controller.LogoutController;import com.withub.demo.controller.ReplyLoginController;import com.withub.demo.plugin.KissoJFinalPlugin;/** * Created by Administrator on 2016/12/24 0024. */public class DemoConfig extends JFinalConfig { //配置设置 @Override public void configConstant(Constants constants) { constants.setDevMode(true); constants.setEncoding("utf-8"); } //配置路由 @Override public void configRoute(Routes routes) { routes.add("/", IndexController.class); routes.add("/login", LoginController.class); routes.add("/logout", LogoutController.class); routes.add("/reply", ReplyLoginController.class); } @Override public void configPlugin(Plugins plugins) { KissoJFinalPlugin kissoJFinalPlugin = new KissoJFinalPlugin(); //初始化插件 plugins.add(kissoJFinalPlugin); } @Override public void configInterceptor(Interceptors interceptors) { } @Override public void configHandler(Handlers handlers) { }}
插件代码如下
package com.withub.demo.plugin;import com.baomidou.kisso.web.WebKissoConfigurer;import com.jfinal.plugin.IPlugin;import org.slf4j.Logger;import org.slf4j.LoggerFactory;/** * Created by Administrator on 2016/12/26 0026. */public class KissoJFinalPlugin implements IPlugin{ private static final Logger logger = LoggerFactory.getLogger(KissoJFinalPlugin.class); //开始 @Override public boolean start() { /*进行初始化*/ WebKissoConfigurer webKissoConfigurer = new WebKissoConfigurer("sso.properties"); webKissoConfigurer.setRunMode("test_mode"); webKissoConfigurer.initKisso(); logger.info("插件初始化完成!"); return true; } //结束 @Override public boolean stop() { logger.info("插件销毁!"); return true; }}
拦截器代码如下
package com.withub.demo.interceptor;import com.baomidou.kisso.SSOConfig;import com.baomidou.kisso.SSOHelper;import com.baomidou.kisso.Token;import com.baomidou.kisso.web.interceptor.KissoAbstractInterceptor;import com.jfinal.aop.Interceptor;import com.jfinal.aop.Invocation;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;/** * Created by Administrator on 2016/12/26 0026. */public class SSOJFinalInterceptor extends KissoAbstractInterceptor implements Interceptor{ private static final Logger log = LoggerFactory.getLogger(SSOJFinalInterceptor.class); @Override public void intercept(Invocation invocation) { log.info("开始拦截!验证登陆."); HttpServletRequest request = invocation.getController().getRequest(); HttpServletResponse response = invocation.getController().getResponse(); Token token = SSOHelper.getToken(request); if(token == null){ if("XMLHttpRequest".equals(request.getHeader("X-Requested-With"))){ //处理ajax请求 //如果未认证返回401 getHandlerInterceptor().preTokenIsNullAjax(request,response); log.info("拦截ajax请求.处理中....."); }else if("APP".equals(request.getHeader("PLATFORM"))){ //采用ajax处理方式 getHandlerInterceptor().preTokenIsNullAjax(request,response); log.info("处理APP请求!"); }else{ //普通请求 try { log.info("拒绝请求:"+request.getRequestURI()); SSOHelper.clearRedirectLogin(request,response); } catch (IOException e) { e.printStackTrace(); } } }else{ /* * 正常请求,request 设置 token 减少二次解密 */ request.setAttribute(SSOConfig.SSO_TOKEN_ATTR,token); invocation.invoke(); } }}
核心:应答控制器replyControll
代码如下
package com.withub.demo.controller;import com.baomidou.kisso.AuthToken;import com.baomidou.kisso.SSOConfig;import com.baomidou.kisso.SSOHelper;import com.baomidou.kisso.Token;import com.baomidou.kisso.common.SSOProperties;import com.jfinal.core.Controller;import org.slf4j.Logger;import org.slf4j.LoggerFactory;/** * Created by Administrator on 2016/12/26 0026. */public class ReplyLoginController extends Controller { private static final Logger log = LoggerFactory.getLogger(ReplyLoginController.class); public void index(){ StringBuffer buffer = new StringBuffer(getRequest().getParameter("callback")).append("({\"msg\":\""); log.info("回复请求!"); Token token = SSOHelper.getToken(getRequest()); if(token != null){ //从请求中拿到询问数据 String askData = getRequest().getParameter("askData"); if(askData != null && !"".equals(askData)){ //拿到令牌 AuthToken authToken = SSOHelper.replyCiphertext(getRequest(), askData); log.info("拿到令牌!"); //拿到配置文件 SSOProperties ssoProperties = SSOConfig.getSSOProperties(); if(authToken != null){ //验证令牌 AuthToken verify = authToken.verify(ssoProperties.get("sso.defined." + authToken.getApp() + "_public_key")); log.info("验证令牌!"); //验证通过 if(verify != null){ log.info("令牌验证通过!正在生成回复令牌!"); verify.setUid(token.getUid()); verify.setTime(token.getTime()); //令牌签名 verify.sign(ssoProperties.get("sso.defined.sso_private_key")); buffer.append(verify.encryptAuthToken()); } } }else{ //伪造信息,拒绝登陆 buffer.append("-2"); } }else{ //用户没有登陆 buffer.append("-1"); } buffer.append("\"})"); renderJson(buffer.toString()); }}
登陆控制器
代码如下
package com.withub.demo.controller;import com.baomidou.kisso.SSOHelper;import com.baomidou.kisso.SSOToken;import com.baomidou.kisso.Token;import com.baomidou.kisso.common.IpHelper;import com.baomidou.kisso.common.util.HttpUtil;import com.baomidou.kisso.web.waf.request.WafRequestWrapper;import com.jfinal.core.Controller;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import java.util.UUID;/** * Created by Administrator on 2016/12/26 0026. *///登陆不用拦截public class LoginController extends Controller { private static final Logger log = LoggerFactory.getLogger(LoginController.class); public void index(){ Token token = SSOHelper.getToken(getRequest()); //令牌不为空,让用户直接访问主页,免登陆. if(token != null){ redirect("/"); return; } //判断是否是POST提交 if(HttpUtil.isPost(getRequest())){ //包装request请求 WafRequestWrapper wafRequestWrapper = new WafRequestWrapper(getRequest()); String name = wafRequestWrapper.getParameter("name"); String password = wafRequestWrapper.getParameter("password"); //验证账号密码,此处暂时不用去数据库校验 if("test".equals(name) && "test".equals(password)){ token = new SSOToken(); token.setUid(UUID.randomUUID().toString()); token.setIp(IpHelper.getIpAddr(getRequest())); token.setId(UUID.randomUUID().toString()); //保存token立即销毁信任的JSESSIONID SSOHelper.setSSOCookie(getRequest(),getResponse(),token,true); redirect("/index.html"); return; } } render("/login.html"); }}
主页控制器
package com.withub.demo.controller;import com.baomidou.kisso.SSOHelper;import com.baomidou.kisso.Token;import com.jfinal.aop.Before;import com.jfinal.core.Controller;import com.withub.demo.interceptor.SSOJFinalInterceptor;import org.slf4j.Logger;import org.slf4j.LoggerFactory;/** * Created by Administrator on 2016/12/24 0024. */@Before(SSOJFinalInterceptor.class)public class IndexController extends Controller { private static final Logger log = LoggerFactory.getLogger(IndexController.class); public void index(){ log.info("进入主页!"); //从request中拿到token,反正解密。 Token token = SSOHelper.attrToken(getRequest()); if(token != null){ log.info("登陆令牌UID"+token.getUid()); log.info("登陆令牌IP地址"+token.getIp()); render("index.html"); return; } render("login.html"); }}
sso系统配置完成,接下来该配置子系统了(我反正是这么理解的)
配置文件如下
################ SSOConfig file #################sso.role=mysso.secretkey=h2wmABdfM7i3K801mysso.cookie.domain=.web.comsso.login.url=http://sso.test.com:8080/login.html# crossdomain secretkeysso.authcookie.secretkey=Lg8V51188n0709i5l81# userConfig definedsso.defined.askurl=http://sso.test.com:8080/replysso.defined.oklogin=http://my.web.com:8099/oksso.defined.my_private_key=MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMp4ORF5r+mBfYrpX944JDyQiaKof5CQ43H65tWS8wT2avQjiUSU2vweXVDbMRD7PPjOAPI5aiIIHFLBqAE9Nq17Xloyz66mUkvvhJxbmB24FhyhB8dREL85EIUahrljrTj2nWWGjDfXIqQoY1NhBi6l2VHgcVuoRI48UzAWcbSBAgMBAAECgYAtLeaOH7lBQcPh23GpBJ4RZa9QvIi6mZonNPWNct0HnnT/RW67/vtehugLwt2QDH/uhQlxA57LOUQYs13p6N7qMZ+4YY592hw4hrJUEAuuORU+wKWnr+wVQNm6Qc9Qf7axM6B5NgtLPbf0R7M53vgHHMyJh2tJKrY3RUdBbsUugQJBAObj3+B7v2QVKKPZlYvICwbKZAUcb1qZtPjtw7+aDah0EEqkaYD0ytmjl2esoknPySN2gbouc+nDvYZopFLgiDMCQQDgfRqCYfMHhjHPHoOwco3ZAevDDe22QksBIkfgFB9srEJCWauFyvB5PTG6+wFv94zqy3R92C6AVaWn8Ae8uqx7AkBkroWXfB7PY7KfEGh31bmJMoQ+/lFIbrJNwlCTonfGNyZLhjpDc3tpQD7rhIoYKbWJ80lKiKsfCq4AiGzvft2lAkEAqcBQDGmu0XC7N2hWolVtR7x5H8znhNuKRfg7K4lr3cxAalXOKuSzhKoucbqecqFZsK5aj1Kqjya0llIeN6tdAwJAImLxsxLxhk6dc8slEo8ObLAWWWkRZNiXCpr+2aWspVx1cK3GRtAa+0Q7X0TiA62/CrlWR/xJHvDI/+I9mcxJKg==sso.defined.my_public_key=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDKeDkRea/pgX2K6V/eOCQ8kImiqH+QkONx+ubVkvME9mr0I4lElNr8Hl1Q2zEQ+zz4zgDyOWoiCBxSwagBPTate15aMs+uplJL74ScW5gduBYcoQfHURC/ORCFGoa5Y6049p1lhow31yKkKGNTYQYupdlR4HFbqESOPFMwFnG0gQIDAQABsso.defined.sso_public_key=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCDZmAZgJcQV0XjBOk/CB2nR+AXXyVMdcErLgz5LYb/g/Ar7tiHhYlGk69/mlItDnvHxeV/t7ibEqwvQnlDiM6BsYW/9HBzYWiF54D7hxd2MUWqNit232pS5XlmzurrFmqhSomrR0KKJHoA3HIsIGJ/AT9xzDb93GqPtDm6Yt24fwIDAQAB
这里的公钥与私钥的作用上文已经解释了,不在赘述。这里多了两个属性,一个是sso.defined.askurl,另一个是sso.defined.oklogin。这两个的作用分别是,向sso发送询问用户是否登陆的url,另一个是用于接受sso系统发送的应答数据。
配置jfinal
代码如下
package com.withub.jfinal.config;import com.jfinal.config.*;import com.jfinal.render.ViewType;import com.withub.jfinal.controller.AskController;import com.withub.jfinal.controller.IndexController;import com.withub.jfinal.controller.OkController;import com.withub.jfinal.plugin.KissoPlugin;/** * Created by Administrator on 2016/12/26 0026. */public class SSXConfig extends JFinalConfig { @Override public void configConstant(Constants constants) { constants.setViewType(ViewType.JSP); } @Override public void configRoute(Routes routes) { routes.add("/", IndexController.class); routes.add("/ask", AskController.class); routes.add("ok", OkController.class); } @Override public void configPlugin(Plugins plugins) { KissoPlugin kissoPlugin = new KissoPlugin(); plugins.add(kissoPlugin); } @Override public void configInterceptor(Interceptors interceptors) { } @Override public void configHandler(Handlers handlers) { }}
插件代码如下
package com.withub.jfinal.plugin;import com.baomidou.kisso.web.WebKissoConfigurer;import com.jfinal.plugin.IPlugin;/** * Created by Administrator on 2016/12/26 0026. */public class KissoPlugin implements IPlugin{ @Override public boolean start() { WebKissoConfigurer webKissoConfigurer = new WebKissoConfigurer("ssx.properties"); webKissoConfigurer.setRunMode("test_mode"); webKissoConfigurer.initKisso(); return true; } @Override public boolean stop() { return true; }}
拦截器代码如下
package com.withub.jfinal.interceptor;import com.baomidou.kisso.SSOConfig;import com.baomidou.kisso.SSOHelper;import com.baomidou.kisso.Token;import com.baomidou.kisso.web.interceptor.KissoAbstractInterceptor;import com.jfinal.aop.Interceptor;import com.jfinal.aop.Invocation;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;/** * Created by Administrator on 2016/12/26 0026. */public class KissoInterceptor extends KissoAbstractInterceptor implements Interceptor { private static final Logger log = LoggerFactory.getLogger(KissoInterceptor.class); @Override public void intercept(Invocation invocation) { HttpServletRequest request = invocation.getController().getRequest(); HttpServletResponse response = invocation.getController().getResponse(); Token token = SSOHelper.getToken(request); if(token == null){ if("XMLHttpRequest".equals(request.getHeader("X-Requested-With"))){ //处理ajax请求 //如果未认证返回401 getHandlerInterceptor().preTokenIsNullAjax(request,response); log.info("拦截ajax请求.处理中....."); }else if("APP".equals(request.getHeader("PLATFORM"))){ //采用ajax处理方式 getHandlerInterceptor().preTokenIsNullAjax(request,response); log.info("处理APP请求!"); }else{ //普通请求 log.info("拒绝请求:"+request.getRequestURI()); //重定向到询问控制器,询问是否登陆 try { response.sendRedirect("/ask"); } catch (IOException e) { e.printStackTrace(); } } }else{ request.setAttribute(SSOConfig.SSO_TOKEN_ATTR,token); invocation.invoke(); } }}
这个拦截器与上面的sso中的拦截器稍微有点区别,一个是用户没有登陆就让用户跳转到登陆的页面,然后这里的拦截器并不是直接让用户跳转到登陆页面,调到ask控制器,向sso询问用户是否登陆。
主页控制器代码如下
package com.withub.jfinal.controller;import com.jfinal.aop.Before;import com.jfinal.core.Controller;import com.withub.jfinal.interceptor.KissoInterceptor;/** * Created by Administrator on 2016/12/26 0026. */@Before(KissoInterceptor.class)public class IndexController extends Controller { public void index(){ render("/index.html"); }}
ask控制器代码如下
package com.withub.jfinal.controller;import com.baomidou.kisso.AuthToken;import com.baomidou.kisso.SSOConfig;import com.baomidou.kisso.SSOHelper;import com.baomidou.kisso.common.SSOProperties;import com.jfinal.core.Controller;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import java.io.IOException;/** * Created by Administrator on 2016/12/26 0026. */public class AskController extends Controller { private static final Logger log = LoggerFactory.getLogger(AskController.class); //向验证服务器发送询问请求 public void index() throws IOException { SSOProperties ssoProperties = SSOConfig.getSSOProperties(); log.info("向认证服务器发送询问,询问是否登陆!"); AuthToken authToken = SSOHelper.askCiphertext(getRequest(), getResponse(), ssoProperties.get("sso.defined.my_private_key")); //askurl 询问 sso 是否登录地址 setAttr("askurl",ssoProperties.get("sso.defined.askurl")); //askTxt 询问 token 密文 setAttr("askData",authToken.encryptAuthToken()); //my 确定是否登录地址 setAttr("okurl",ssoProperties.get("sso.defined.oklogin")); render("/ask.jsp"); }}
这里我们并没用直接向sso发送请求而是返回了一个视图,原因是,直接用java发送http请求cookie带不过去。我们来看看ask.jsp这个页面吧。
<%@ page contentType="text/html;charset=UTF-8" language="java" %><html><head> <title>页面正在跳转中.....</title> <script type="text/javascript" src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script> <script type="text/javascript"> function askLogin(askUrl,askData,okUrl) { $.ajax( { 'type':'post', 'url':askUrl, 'data':{ 'askData':askData }, 'dataType':'jsonp', 'jsonp':'callback', 'success':function (data) { var msg = data.msg; if(msg != 201){ $.ajax({ 'type':'post', 'url':okUrl, 'data':{ 'replyText':data.msg }, 'dataType':'json', 'success':function (data) { window.location.href = data.url; } }); }else{ window.location.href = "http://www.ddk.com:8899/login"; } } }); } $(function () { askLogin('${askUrl}','${askData}','${okUrl}'); window.setTimeout(function () { window.location.href = "http://www.ddk.com:8899/timeout.html"; },30000) }); </script></head><body> <h1>页面正在跳转中..........</h1></body></html>
这里面关键的就是js代码,为了解决跨域访问的问题,采用了jsonp的格式来请求sso服务器。如果验证通过了将会自动的跳转到okUrl这里去。jsp中的参数全是从request域中获取的。详情可以看上文的ask控制器的代码。
如果验证成功的话会到okUrl这里来,我们来看看okUrl里面有什么。
package com.withub.jfinal.ddk.controller;import com.baomidou.kisso.AuthToken;import com.baomidou.kisso.SSOConfig;import com.baomidou.kisso.SSOHelper;import com.baomidou.kisso.SSOToken;import com.baomidou.kisso.common.IpHelper;import com.baomidou.kisso.common.SSOProperties;import com.jfinal.core.Controller;import com.jfinal.kit.StrKit;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.util.HashMap;import java.util.Map;import java.util.UUID;/** * Created by Administrator on 2016/12/28 0028. */public class OkController extends Controller { public void index(){ //从请求中拿到sso服务器的响应数据 String replyText = getPara("replyText"); SSOProperties ssoProperties = SSOConfig.getSSOProperties(); Map<String,Object> result = new HashMap<>(); HttpServletRequest request = getRequest(); HttpServletResponse response = getResponse(); result.put("url",ssoProperties.get("sso.login.url")); if(StrKit.notBlank(replyText)){ //验证令牌合法性 AuthToken ok = SSOHelper.ok(request, response, replyText, ssoProperties.get("sso.defined.ddk_public_key"), ssoProperties.get("sso.defined.sso_public_key")); if(ok != null){ //验证通过.生成本域的令牌 SSOToken ssoToken = new SSOToken(); ssoToken.setIp(IpHelper.getIpAddr(request)); ssoToken.setId(UUID.randomUUID().toString().replaceAll("-","")); SSOHelper.setSSOCookie(request,response,ssoToken,true); result.put("url",ssoProperties.get("sso.index.url")); } } renderJson(result); }}
上面的逻辑很简单,就不多的赘述了。验证完成后就会返回一个json,然后ask.jsp页面拿到json就会跳转页面到主页。
好了这就完成了简单的跨域单点登陆了。
萌新一枚,多多指教。
- jfinal与kisso跨域单点登陆
- 关于JFinal与kisso集成使用心得
- PHP版单点登陆实现方案 SS0单点登陆 跨域登陆
- 单点登陆简单实现(完全跨域、单点退出)
- 跨域单点登陆之XMLHttpRequest详解
- 单点登陆之session跨域问题
- 单点登陆与实现原理
- JForum单点登陆原理与配置
- 单点登陆_配置客户端与服务器端
- 单点登陆原理与简单实现
- ucenter实现跨域单点登陆的方法
- ucenter实现跨域单点登陆的方法
- 单点登陆
- 单点登陆
- 单点登陆
- 单点登陆
- 单点登陆
- 单点登陆
- mysql中explain查看sql语句执行效率
- Objective-C - 属性类型修饰符
- asp管理员新闻删除功能
- Struts知识点概况(二)
- 关于3dmax模型导入到u3d中时,坐标会旋转的问题
- jfinal与kisso跨域单点登陆
- 安卓实战之如何快速搭建app架构
- MYSQL学习笔记-基本操作
- spring boot 配置druid连接池
- secureCRT 设置背景色等操作
- 写Java文档的理由、建议和技巧
- 1.MATLAB图像处理基础知识
- 数据结构课程设计--电子投票系统
- JavaWeb中request与response的认知