完成sso单点登录demo

This commit is contained in:
fanxb 2019-03-14 17:29:21 +08:00
parent 6dc9c359e3
commit a11ed17417
17 changed files with 137 additions and 42 deletions

View File

@ -28,6 +28,22 @@
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId> <artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency> </dependency>
<dependency> <dependency>

View File

@ -3,6 +3,9 @@ package com.infinova.sso.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager; import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching; import org.springframework.cache.annotation.EnableCaching;
@ -12,11 +15,13 @@ import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter; import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.JedisPoolConfig;
import java.time.Duration; import java.time.Duration;
@ -31,6 +36,28 @@ import java.time.Duration;
@Configuration @Configuration
public class RedisConfig extends CachingConfigurerSupport { public class RedisConfig extends CachingConfigurerSupport {
private static Logger logger = LoggerFactory.getLogger(RedisConfig.class);
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.password}")
private String password;
@Value("${spring.redis.port}")
private int port;
@Value("${spring.redis.timeout}")
private int timeout;
@Value("${spring.redis.database}")
private int database;
@Value("${spring.redis.jedis.pool.max-idle}")
private int maxIdle;
@Value("${spring.redis.jedis.pool.min-idle}")
private int minIdle;
@Value("${spring.redis.jedis.pool.max-wait}")
private long maxWaitMillis;
@Value("${spring.redis.jedis.pool.max-active}")
private int maxActive;
/** /**
* 设置缓存管理器这里可以配置默认过期时间等 * 设置缓存管理器这里可以配置默认过期时间等
* *
@ -38,11 +65,11 @@ public class RedisConfig extends CachingConfigurerSupport {
* @return * @return
*/ */
@Bean @Bean
public CacheManager cacheManager(RedisConnectionFactory connectionFactory) { public CacheManager cacheManager(JedisConnectionFactory jedisConnectionFactory) {
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration
.defaultCacheConfig() .defaultCacheConfig()
.entryTtl(Duration.ofSeconds(60)); .entryTtl(Duration.ofSeconds(60));
RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory); RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(jedisConnectionFactory);
RedisCacheManager manager = new RedisCacheManager(redisCacheWriter, redisCacheConfiguration); RedisCacheManager manager = new RedisCacheManager(redisCacheWriter, redisCacheConfiguration);
return manager; return manager;
} }
@ -64,4 +91,27 @@ public class RedisConfig extends CachingConfigurerSupport {
template.afterPropertiesSet(); template.afterPropertiesSet();
return template; return template;
} }
@Bean
public JedisConnectionFactory jedisConnectionFactory() {
logger.info("jedisConnectionFactory:初始化了");
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxIdle(maxIdle);
config.setMinIdle(minIdle);
config.setMaxWaitMillis(maxWaitMillis);
config.setMaxTotal(maxActive);
//链接耗尽时是否阻塞默认true
config.setBlockWhenExhausted(true);
//是否启用pool的jmx管理功能默认true
config.setJmxEnabled(true);
JedisConnectionFactory factory = new JedisConnectionFactory();
factory.setPoolConfig(config);
factory.setHostName(host);
factory.setPort(port);
factory.setPassword(password);
factory.setDatabase(database);
factory.setTimeout(timeout);
return factory;
}
} }

View File

@ -1,10 +1,8 @@
package com.infinova.sso.controller; package com.infinova.sso.controller;
import com.alibaba.fastjson.JSONArray;
import com.infinova.sso.entity.ReturnEntity; import com.infinova.sso.entity.ReturnEntity;
import com.infinova.sso.entity.User; import com.infinova.sso.entity.User;
import com.infinova.sso.service.JwtService; import com.infinova.sso.service.JwtService;
import com.infinova.sso.util.HttpUtil;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@ -34,14 +32,13 @@ public class JwtController {
return ReturnEntity.successResult(token); return ReturnEntity.successResult(token);
} }
@PostMapping("/checkJwt") @GetMapping("/checkJwt")
public ReturnEntity checkJwt(String token) { public ReturnEntity checkJwt(String token) {
return ReturnEntity.successResult(service.checkJwt(token)); return ReturnEntity.successResult(service.checkJwt(token));
} }
@GetMapping("/inValid") @GetMapping("/inValid")
public ReturnEntity inValid() { public ReturnEntity inValid(String token) {
String token = HttpUtil.getData(JwtService.JWT_KEY);
service.inValid(token); service.inValid(token);
return ReturnEntity.successResult(null); return ReturnEntity.successResult(null);
} }

View File

@ -1,8 +1,7 @@
package com.infinova.sso.util; package com.infinova.sso.util;
import com.alibaba.fastjson.JSON;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -18,20 +17,23 @@ import java.util.concurrent.TimeUnit;
public class RedisUtil { public class RedisUtil {
private static final int DEFAULT_EXPIRE_TIME = 60 * 1000; private static final int DEFAULT_EXPIRE_TIME = 60 * 1000;
public static RedisTemplate<String, String> redisTemplate; public static StringRedisTemplate redisTemplate;
@Autowired @Autowired
public void setRedisTemplate(RedisTemplate<String, String> redisTemplate) { public void setRedisTemplate(StringRedisTemplate redisTemplate) {
RedisUtil.redisTemplate = redisTemplate; RedisUtil.redisTemplate = redisTemplate;
} }
@Autowired
/** /**
* 设置键值对使用默认过期时间 * 设置键值对使用默认过期时间
* *
* @param key * @param key
* @param value * @param value
*/ */
public static void set(String key, Object value) { public static void set(String key, String value) {
set(key, value, DEFAULT_EXPIRE_TIME); set(key, value, DEFAULT_EXPIRE_TIME);
} }
@ -42,8 +44,8 @@ public class RedisUtil {
* @param value value * @param value value
* @param expireTime 过期时间 * @param expireTime 过期时间
*/ */
public static void set(String key, Object value, long expireTime) { public static void set(String key, String value, long expireTime) {
redisTemplate.opsForValue().set(key, JSON.toJSONString(value)); redisTemplate.opsForValue().set(key, value);
redisTemplate.expire(key, expireTime, TimeUnit.MILLISECONDS); redisTemplate.expire(key, expireTime, TimeUnit.MILLISECONDS);
} }

View File

@ -9,22 +9,22 @@ spring:
type: redis type: redis
redis: redis:
database: 0 database: 0
host: 192.168.1.100 host: 10.82.27.177
port: 6379 port: 6379
password: password:
# 连接超时时间ms) # 连接超时时间ms)
timeout: 1000ms timeout: 5000
# 高版本springboot中使用jedis或者lettuce # 高版本springboot中使用jedis或者lettuce
jedis: jedis:
pool: pool:
# 连接池最大连接数(负值表示无限制) # 连接池最大连接数(负值表示无限制)
max-active: 8 max-active: 8
# 连接池最大阻塞等待时间(负值无限制) # 连接池最大阻塞等待时间(负值无限制)
max-wait: 5000ms max-wait: 5000
# 最大空闲链接数 # 最大空闲链接数
max-idle: 8 max-idle: 8
# 最小空闲链接数 # 最小空闲链接数
min-idle: 0 min-idle: 1
mvc: mvc:
static-path-pattern: /static/** static-path-pattern: /static/**
# jwt过期时间单位分钟 # jwt过期时间单位分钟

View File

@ -25,9 +25,10 @@
} else { } else {
//有token检查token是否还有效 //有token检查token是否还有效
$.get("/sso/checkJwt?token=" + localStorage.getItem("token"), function (res) { $.get("/sso/checkJwt?token=" + localStorage.getItem("token"), function (res) {
if (res.code === 1) { console.log(res);
if (res.data === true) {
alert('已登录,跳转到回调页面'); alert('已登录,跳转到回调页面');
window.location.href = getUrlParam("redirect") + "&token=" + getToken(); window.location.href = getUrlParam("redirect") + "?token=" + localStorage.getItem("token");
} else { } else {
goLogin(); goLogin();
} }

View File

@ -25,9 +25,9 @@
data: JSON.stringify({name: name, password: password}), data: JSON.stringify({name: name, password: password}),
success: function (res) { success: function (res) {
if (res.code === 1) { if (res.code === 1) {
setToken(res.data); localStorage.setItem("token", res.data);
alert("登录成功,跳转到回调地址"); alert("登录成功,跳转到回调地址");
window.location.href = getUrlParam("redirect") + "&token=" + res.data; window.location.href = getUrlParam("redirect") + "?token=" + res.data;
} else { } else {
alert("账号密码错误"); alert("账号密码错误");
} }

View File

@ -2,7 +2,6 @@ package com.example.sysa.controller;
import com.example.sysa.entity.ReturnEntity; import com.example.sysa.entity.ReturnEntity;
import com.example.sysa.entity.UserContext; import com.example.sysa.entity.UserContext;
import com.example.sysa.filter.LoginFilter;
import com.example.sysa.util.HttpClient; import com.example.sysa.util.HttpClient;
import com.example.sysa.util.UserContextHolder; import com.example.sysa.util.UserContextHolder;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
@ -31,7 +30,7 @@ public class Main {
@RequestMapping("/logout") @RequestMapping("/logout")
public ReturnEntity logout() throws Exception { public ReturnEntity logout() throws Exception {
UserContext context = UserContextHolder.get(); UserContext context = UserContextHolder.get();
HttpClient.get(serverHost + "/clearToken?token=" + context.getToken()); HttpClient.get(serverHost + "/inValid?token=" + context.getToken());
return null; return null;
} }
} }

View File

@ -17,8 +17,6 @@ import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.io.IOException; import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/** /**
@ -76,7 +74,7 @@ public class LoginFilter implements Filter {
return false; return false;
} }
JSONObject object = HttpClient.get(serverHost + "/checkJwt?token=" + jwt); JSONObject object = HttpClient.get(serverHost + "/checkJwt?token=" + jwt);
return object.getInteger("code") == 1; return object.getBoolean("data");
} catch (Exception e) { } catch (Exception e) {
logger.error("向认证中心请求失败", e); logger.error("向认证中心请求失败", e);
return false; return false;

View File

@ -2,7 +2,7 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>系统A</title> <title>系统</title>
</head> </head>
<body> <body>
<div id="currentHost"></div> <div id="currentHost"></div>
@ -14,16 +14,12 @@
<script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script> <script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="https://cdn.bootcss.com/Base64/1.0.2/base64.min.js"></script> <script src="https://cdn.bootcss.com/Base64/1.0.2/base64.min.js"></script>
<script> <script>
$('#currentHost').text(location.origin);
var token = getUrlParam("token");
if (token != null && token.trim().length > 0) {
localStorage.setItem("token", token);
}
test(); test();
var info = localStorage.getItem("token").split(".")[1]; var info = localStorage.getItem("token").split(".")[1];
var userName = JSON.parse(window.atob(info)).name; var userName = JSON.parse(window.atob(info)).name;
$('#loginStatus').text(userName); $('#loginStatus').text(userName);
$('#currentHost').text("当前ip端口" + location.origin);
//测试token是否有效 //测试token是否有效
@ -38,7 +34,7 @@
//注销登录 //注销登录
function clearToken() { function clearToken() {
$.get("/logout?token=" + getToken(), function (res) { $.get("/logout?token=" + localStorage.getItem("token"), function (res) {
localStorage.removeItem("token"); localStorage.removeItem("token");
goToLoginServer(); goToLoginServer();
}) })
@ -46,14 +42,8 @@
function goToLoginServer() { function goToLoginServer() {
alert("当前无登录信息,跳转到认证中心"); alert("当前无登录信息,跳转到认证中心");
location.href = encodeURI("http://localhost:8080/sso/static/index.html?order=checkLogin&redirect=" + window.location.href); localStorage.setItem("redirect", location.href);
} location.href = encodeURI("http://localhost:8080/sso/static/index.html?order=checkLogin&redirect=" + window.location.origin + "/static/redirect.html");
function getUrlParam(name) {
var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); //构造一个含有目标参数的正则表达式对象
var r = window.location.search.substr(1).match(reg); //匹配目标参数
if (r != null) return unescape(r[2]);
return null; //返回参数值
} }
</script> </script>

View File

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>系统</title>
</head>
<body>
<script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<script>
//本页面用于回调中转
var token = getUrlParam("token");
localStorage.setItem("token", token);
location.replace(localStorage.getItem("redirect"))
function getUrlParam(name) {
var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); //构造一个含有目标参数的正则表达式对象
var r = window.location.search.substr(1).match(reg); //匹配目标参数
if (r != null) return unescape(r[2]);
return null; //返回参数值
}
</script>
</body>
</html>

View File

@ -0,0 +1,2 @@
server:
port: 10011

View File

@ -0,0 +1,3 @@
server:
port: 10012

View File

@ -0,0 +1,5 @@
server:
port: 10001
spring:
application:
name: licensingservice

View File

@ -0,0 +1,2 @@
server:
port: 10012

View File

@ -0,0 +1,3 @@
server:
port: 10012

View File

@ -0,0 +1,3 @@
spring:
application:
name: organizationservice