首先感谢xxl-sso开源项目,传送门 xxl-soo官网.
前言:由于我们公司项目比较多,登陆基本上都是工号加密码,所以想做一个单点系统,登陆A系统之后就可以直接进入其他任意相关系统无需登陆,一个系统退出,所有系统退出,这里找了很多资料和博客,最终选择xxl-sso做集成
大家把项目下载下来后更xxl-sso-server中的application.properties文件
### web
server.port=8080
server.servlet.context-path=/xxl-sso-server
### resources
spring.mvc.servlet.load-on-startup=0
spring.mvc.static-path-pattern=/static/**
spring.resources.static-locations=classpath:/static/
### freemarker
spring.freemarker.templateLoaderPath=classpath:/templates/
spring.freemarker.suffix=.ftl
spring.freemarker.charset=UTF-8
spring.freemarker.request-context-attribute=request
spring.freemarker.settings.number_format=0.##########
### xxl-sso
xxl.sso.redis.address=redis://127.0.0.1:6379
xxl.sso.redis.expire.minute=1440
主要更改一下这个redis的地址即可
他这边还给了两个实例项目xxl-sso-web-sample-springboot和xxl-sso-token-sample-springboot,我这边使用xxl-sso-web-sample-springboot做的测试,先更改application.properties文件
### web
server.port=8082
server.servlet.context-path=/xxl-sso-web-sample-springboot
### resources
spring.mvc.servlet.load-on-startup=0
spring.mvc.static-path-pattern=/static/**
spring.resources.static-locations=classpath:/static/
### freemarker
spring.freemarker.templateLoaderPath=classpath:/templates/
spring.freemarker.suffix=.ftl
spring.freemarker.charset=UTF-8
spring.freemarker.request-context-attribute=request
spring.freemarker.settings.number_format=0.##########
### xxl-sso
xxl.sso.server=http://localhost:8080/xxl-sso-server
xxl.sso.logout.path=/logout
xxl-sso.excluded.paths=
xxl.sso.redis.address=redis://127.0.0.1:6379
这里主要更改xxl.sso.server,这个改成你xxl-sso-server的启动地址即可,还需改一下redis地址
这里启动项目一个8080的http://localhost:8080/xxl-sso-server/login,一个8081的http://localhost:8081/xxl-sso-web-sample-springboot
在8080未登陆情况下,8081直接登陆会跳转至8080登陆页面,任意一个系统登陆成功后,同浏览器直接可以输入其他系统地址,无需登陆,一个系统退出,所有系统都退出
这里基本上按照dome走就搭建完毕了,接下来进入我们自己的项目
上一步中的http://localhost:8081/xxl-sso-web-sample-springboot就是一个springboot项目这里我们集成到自己项目中去
首先添加maven依赖,pom中添加,我这里用到springboot版本是>2.3.0的版本
com.xuxueli
xxl-sso-core
1.1.0
配置application.properties文件中添加xxl-sso相关配置
xxl.sso.server=http://localhost:8080/xxl-sso-server
xxl.sso.logout.path=/logout
xxl-sso.excluded.paths=
xxl.sso.redis.address=redis://127.0.0.1:6379
这里xxl-sso.excluded.paths可以配置无需拦截的一些路径,如文件下载,这种公共对外接口无需登陆的路径,多个用,隔开
添加XxlSsoConfig.java配置类
package com.xxl;
import com.xxl.sso.core.conf.Conf;
import com.xxl.sso.core.filter.XxlSsoWebFilter;
import com.xxl.sso.core.util.JedisUtil;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author xuxueli 2018-11-15
*/
@Configuration
public class XxlSsoConfig implements DisposableBean {
@Value("${xxl.sso.server}")
private String xxlSsoServer;
@Value("${xxl.sso.logout.path}")
private String xxlSsoLogoutPath;
@Value("${xxl-sso.excluded.paths}")
private String xxlSsoExcludedPaths;
@Value("${xxl.sso.redis.address}")
private String xxlSsoRedisAddress;
@Bean
public FilterRegistrationBean xxlSsoFilterRegistration() {
// xxl-sso, redis init
JedisUtil.init(xxlSsoRedisAddress);
// xxl-sso, filter init
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setName("XxlSsoWebFilter");
registration.setOrder(1);
registration.addUrlPatterns("/*");
registration.setFilter(new XxlSsoWebFilter());
registration.addInitParameter(Conf.SSO_SERVER, xxlSsoServer);
registration.addInitParameter(Conf.SSO_LOGOUT_PATH, xxlSsoLogoutPath);
registration.addInitParameter(Conf.SSO_EXCLUDED_PATHS, xxlSsoExcludedPaths);
return registration;
}
@Override
public void destroy() throws Exception {
// xxl-sso, redis close
JedisUtil.close();
}
}
注意,官方给的模板中用户名密码是写死在后台的,实际我们应用中需要更改为从数据库获取,可以在xxl-sso-server中更改UserServiceImpl,我这边做测试就自己先加了一个用户名密码
我这边是在控制器里面写了个入口,用重定向做了跳转,跳转到我自己的其他项目的主页,因为这个项目中在session中存了用户信息,所以我这边在这里跳转前进行了存储,因为这里是做演示,我这边在xxl-sso-server存的是写死的用户名和密码,这边获取到后再去数据库根据id把用户信息查询到存储全量信息
@RequestMapping("/")
public void index(Model model, HttpServletRequest request,HttpServletResponse response) {
XxlSsoUser xxlUser = (XxlSsoUser) request.getAttribute(Conf.SSO_USER);
request.getSession().setAttribute(ClomnUtil.USERKEY,loginServiceipml.loginByid(Integer.parseInt(xxlUser.getUserid())));
String uri = request.getScheme() + "://" +
request.getServerName() +
":" + request.getLocalPort() +"/menu";
try {
response.sendRedirect(uri);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
上面这一步其实是登陆后做跳转用的,相当于我们输入http://localhost:项目端口/,会直接跳转到8080的xxs-sso中去先登陆,登陆完成后调用我上面的方案去跳转到我的项目主页,加这一步的目的是为了存储我的用户信息到session,方便我后续使用这个用户信息
退出的时候同样,情况我们的session和全局token信息
@GetMapping(value="/loginout")
@ResponseBody
public int getLoginPageOut(HttpServletRequest request) {
request.getSession().removeAttribute(ClomnUtil.USERKEY);
SsoTokenLoginHelper.logout(CookieUtil.getValue(request, "xxl_sso_sessionid"));
return 200;
}
这里的返回信息其实没用,因为调用SsoTokenLoginHelper.logout后会自动调用一个重定向方案跳转到的登陆界面
这一套springboot一体的就完成了,基本上改动很小,改一下配置文件,加一个配置类,登陆、退出的时候根据自己的需求去做特殊处理就完了
我这边还有个项目是使用vue前后端分离的,刚开始集成的时候一直集成不了,因为涉及到跨域,前后端分离登一大堆问题,好在后来都解决了,下面开始
首先还是一样后端更改application.properties,添加配置类XxlSsoConfig,这里不在重复了,这里说一下我的方案
因为前后端分离的项目,我们前端统一登陆后时没办法直接跳转到VUE的前端页面的,即时跳过去我的相关token也没法给到vue页面,这里统一登陆完成后先进入后端,从后端再跳到登陆页面(也可以是其他空白页面),在这个页面初始化的时候去把相关信息存取到前台的公共变量中,在ajax中去设置统一拦截,请求前去统一加xxl_sso_sessionid和token,一定要加xxl_sso_sessionid不然后台会拦截,但无法跳转到登陆,页面会一直停在这里的,上代码
@RequestMapping("/loginSinge")
public void index(Model model, HttpServletRequest request,HttpServletResponse response) {
XxlSsoUser xxlUser = (XxlSsoUser) request.getAttribute(Conf.SSO_USER);
String xxl_sso_sessionid = CookieUtil.getValue(request, "xxl_sso_sessionid");
sysUserTokenService.createToken(Long.parseLong(xxlUser.getUserid()),xxl_sso_sessionid);
String uri = request.getScheme() + "://localhost:8001"
+"/login#/login?token="+xxl_sso_sessionid;
try {
response.sendRedirect(uri);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 退出
*/
@PostMapping("/sys/logout")
public R logout(HttpServletRequest request) {
sysUserTokenService.logout(getUserId());
SsoTokenLoginHelper.logout(CookieUtil.getValue(request, "token"));
return R.ok();
}
这里//localhost:8001是前端项目的地址,这里方便演示我就先写死了,这里sysUserTokenService.createToken(Long.parseLong(xxlUser.getUserid()),xxl_sso_sessionid);是我本地生成token的方法,我这边为了偷懒直接用xxl-sso的sessionid作为我的token,这里比较麻烦,如果自己生成的话,后面可以重定向的时候?token="+xxl_sso_sessionid;需要再加一个你自己的token,退出也一样,先清自己的token,再清全局token,清完后会自动跳转到登陆
vue页面前端再created的时候调用this.loginSing()
loginSing () {
if(this.$route.query.token!=null){
this.$cookie.set('token', this.$route.query.token)
this.$router.replace({ name: 'home' })
}else{
window.location.href='http://localhost:8080/xxl-sso-server/'
}
}
这边直接从请求中把token获取到存到前台全局变量中
在httpRequest.js中添加
import Vue from 'vue'
import axios from 'axios'
const http = axios.create({
timeout: 1000 * 30,
withCredentials: true,
headers: {
'Content-Type': 'application/json; charset=utf-8'
}
})
/**
* 请求拦截
*/
http.interceptors.request.use(config => {
return config
}, error => {
return Promise.reject(error)
})
主要是xxl_sso_sessionid这个全局token带上即可,然后访问统一登陆入口,登陆成功访问我们自己项目的loginSinge方法,会跳登陆页面然后立即跳到首页,这个很快的,我这个方案是把token放到请求路径中,通过 this.$route.query去获取,可能有点不安全,但功能确实是实现了。另外他这个首页和登陆大家也可以根据需求去更改一下,这个样式…也还行吧,路径xxl-sso-server中src/main/resources下templates里面的login.ftl和index.ftl
大家有问题可以评论区问我,有好的想法也可以评论区提出来,如果对您有用,帮忙点个赞,谢谢啦!