单点登录(Single Sign On),简称为 SSO,是目前比较流行的企业业务整合的解决方案之一。SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。目前市面上有很多实现单点登录的方案,例如CAS,Token颁发校验,Cookie+域名+路径配置,在这里主要是想介绍一下第三种方案的实现方式。
此篇文章支持单域名下的二级域名的单点登陆
开发状态:当前公司项目是一个单体垂直架构,只是集成了了Spring-Session和Redis。
Session:在计算机中,尤其是在网络应用中,称为“会话控制”。Session 对象存储特定用户会话所需的属性及配置信息。这样,当用户在应用程序的 Web 页之间跳转时,存储在 Session 对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。当用户请求来自应用程序的 Web 页时,如果该用户还没有会话,则 Web 服务器将自动创建一个 Session 对象。当会话过期或被放弃后,服务器将终止该会话。Session 对象最常见的一个用法就是存储用户的首选项。例如,如果用户指明不喜欢查看图形,就可以将该信息存储在 Session 对象中。有关使用 Session 对象的详细信息,请参阅“ASP 应用程序”部分的“管理会话”。注意 会话状态仅在支持 cookie 的浏览器中保留。
maven
org.springframework.data spring-data-redis 1.3.2.RELEASE
springboot 中 spring-Session 的注解配置
@Configuration
@EnableRedisHttpSession
public class SessionConfig {
@Bean
public JedisConnectionFactory connectionFactory() {
JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
jedisConnectionFactory.setHostName("***"); // 默认localhost
jedisConnectionFactory.setPort(****); // 默认6379
jedisConnectionFactory.setDatabase(0); // 默认0
jedisConnectionFactory.afterPropertiesSet();
return jedisConnectionFactory;
}
@Bean
public CookieSerializer cookieSerializer(ServletContext servletContext, MySessionCookieConfig sessionCookieConfig) {
DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();
if (servletContext != null) {
if (sessionCookieConfig != null) {
if (sessionCookieConfig.getName() != null)
cookieSerializer.setCookieName(sessionCookieConfig.getName());
if (sessionCookieConfig.getDomain() != null)
cookieSerializer.setDomainName(sessionCookieConfig.getDomain());
if (sessionCookieConfig.getPath() != null)
cookieSerializer.setCookiePath(sessionCookieConfig.getPath());
if (sessionCookieConfig.getMaxAge() != -1)
cookieSerializer.setCookieMaxAge(sessionCookieConfig.getMaxAge());
if (sessionCookieConfig.getDomainPattern() != null)
cookieSerializer.setDomainNamePattern(sessionCookieConfig.getDomainPattern());
if (sessionCookieConfig.getJvmRoute() != null)
cookieSerializer.setJvmRoute(sessionCookieConfig.getJvmRoute());
cookieSerializer.setUseSecureCookie(sessionCookieConfig.isSecure());
cookieSerializer.setUseBase64Encoding(sessionCookieConfig.isUseBase64Encoding());
cookieSerializer.setUseHttpOnlyCookie(sessionCookieConfig.isHttpOnly());
}
}
if (ClassUtils.isPresent(
"org.springframework.security.web.authentication.RememberMeServices",
null)) {
boolean usesSpringSessionRememberMeServices = !ObjectUtils
.isEmpty(this.context
.getBeanNamesForType(SpringSessionRememberMeServices.class));
if (usesSpringSessionRememberMeServices) {
cookieSerializer.setRememberMeRequestAttribute(
SpringSessionRememberMeServices.REMEMBER_ME_LOGIN_ATTR);
}
}
return cookieSerializer;
}
private ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.context = applicationContext;
}
}
import org.springframework.stereotype.Component;
/**
* @author pontus
* @date create in 17:33 2018/10/9
* @description
*/
@Component
public class MyDefaultSessionCookieConfig implements MySessionCookieConfig {
private String name;
private String path;
private String domain;
private String comment;
private int maxAge = -1;
private String domainPattern;
private String jvmRoute;
private boolean httpOnly = true;
private boolean secure = false;
private boolean useBase64Encoding = false;
@Override
public String getDomainPattern() {
return domainPattern;
}
@Override
public void setDomainPattern(String domainPattern) {
this.domainPattern = domainPattern;
}
@Override
public String getJvmRoute() {
return jvmRoute;
}
@Override
public void setJvmRoute(String jvmRoute) {
this.jvmRoute = jvmRoute;
}
@Override
public boolean isUseBase64Encoding() {
return useBase64Encoding;
}
@Override
public void setUseBase64Encoding(boolean useBase64Encoding) {
this.useBase64Encoding = useBase64Encoding;
}
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public String getPath() {
return path;
}
@Override
public void setPath(String path) {
this.path = path;
}
@Override
public String getDomain() {
return domain;
}
@Override
public void setDomain(String domain) {
this.domain = domain;
}
@Override
public String getComment() {
return comment;
}
@Override
public void setComment(String comment) {
this.comment = comment;
}
@Override
public boolean isHttpOnly() {
return httpOnly;
}
@Override
public void setHttpOnly(boolean httpOnly) {
this.httpOnly = httpOnly;
}
@Override
public boolean isSecure() {
return secure;
}
@Override
public void setSecure(boolean secure) {
this.secure = secure;
}
@Override
public int getMaxAge() {
return maxAge;
}
@Override
public void setMaxAge(int maxAge) {
this.maxAge = maxAge;
}
}
import javax.servlet.SessionCookieConfig;
/**
* @author pontus
* @date create in 17:12 2018/10/9
* @description
*/
public interface MySessionCookieConfig extends SessionCookieConfig {
String getDomain();
String getDomainPattern();
void setDomainPattern(String domainPattern);
String getJvmRoute();
void setJvmRoute(String jvmRoute);
boolean isUseBase64Encoding();
void setUseBase64Encoding(boolean useBase64Encoding);
}
import com.xiaotu.util.Redis.RedisParam;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
import org.springframework.session.web.http.CookieSerializer;
import org.springframework.session.web.http.DefaultCookieSerializer;
/**
* @author pontus
* @date create in 14:14 2018/10/9
* @description
*/
@Configuration
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 1800)
public class HttpSessionConfig implements ApplicationContextAware {
@Autowired
RedisParam redisParam;
@Bean
public JedisConnectionFactory connectionFactory() {
JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
jedisConnectionFactory.setHostName(redisParam.getIp()); // 默认localhost
jedisConnectionFactory.setPort(redisParam.getPort()); // 默认6379
jedisConnectionFactory.setDatabase(redisParam.getDatabase()); // 默认0
jedisConnectionFactory.setPassword(redisParam.getPassword());
jedisConnectionFactory.afterPropertiesSet();
return jedisConnectionFactory;
}
@Bean
public CookieSerializer cookieSerializer() {
DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();
cookieSerializer.setCookieName("*****");
cookieSerializer.setDomainName("******");
cookieSerializer.setCookiePath("/");
cookieSerializer.setUseBase64Encoding(false);
return cookieSerializer;
}
private ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.context = applicationContext;
}
}