增加sso单点登录例子

This commit is contained in:
fanxb 2019-03-12 19:17:29 +08:00
parent 47686a30cb
commit 3917829968
22 changed files with 768 additions and 240 deletions

26
1.SSO单点登录/sso/bin/.gitignore vendored Normal file
View File

@ -0,0 +1,26 @@
HELP.md
/target/
!.mvn/wrapper/maven-wrapper.jar
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
/build/

View File

@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>sso</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>sso</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.4</version>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.7.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>CAS</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,28 @@
server:
port: 8081
servlet:
context-path: /sso
spring:
application:
name: SSO
cache:
type: redis
redis:
database: 0
host: 192.168.226.5
port: 6379
password:
# 连接超时时间ms)
timeout: 1000ms
# 高版本springboot中使用jedis或者lettuce
jedis:
pool:
# 连接池最大连接数(负值表示无限制)
max-active: 8
# 连接池最大阻塞等待时间(负值无限制)
max-wait: 5000ms
# 最大空闲链接数
max-idle: 8
# 最小空闲链接数
min-idle: 0

View File

@ -0,0 +1,63 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>认证中心</title>
</head>
<div style="text-align: center;">这里是认证中心主页</div>
<div>
<button onclick="clearToken()">清除token</button>
</div>
<script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="main.js"></script>
<script src="https://cdn.bootcss.com/Base64/1.0.2/base64.js"></script>
<script>
$('#loginStatus').html(getUserName())
function clearToken() {
delete window.localStorage.token;
}
var order = getUrlParam("order");
switch (order) {
case "checkLogin":
checkLogin();
break;
case "updateToken":
updateToken();
break;
default:
console.log("不支持的order:" + order);
}
function checkLogin() {
var token = getToken();
if (token == null) {
goLogin();
} else {
//有token检查token是否还有效
$.get("/checkToken?token=" + getToken(), function (res) {
if (res.code === 1) {
alert('以登录,跳转到回调页面');
window.location.href = getUrlParam("redirect") + "&token=" + getToken();
}else {
goLogin();
}
})
}
}
function goLogin(){
// alert("无认证信息,即将跳转到登录页面");
window.location.href = encodeURI("/login.html?redirect=" + getUrlParam("redirect"));
}
function updateToken() {
var token = getUrlParam("token");
setToken(token);
}
</script>
</body>
</html>

View File

@ -0,0 +1,42 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>认证中心登录页面</title>
</head>
<body>
<div style="width:800px;margin:0 auto">
<input type="text" value="" id="name"/><br/>
<input type="password" value="" id="password"/><br/>
<button id="login" onclick="doLogin()">登录</button>
</div>
<script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="main.js"></script>
<script src="https://cdn.bootcss.com/Base64/1.0.2/base64.min.js"></script>
<script>
function doLogin() {
var name = $('#name').val();
var password = $('#password').val();
password = window.btoa(password);
console.log(name, password);
$.ajax({
type: 'post',
url: "/sso/login",
contentType: "application/json",
dataType: 'json',
data: JSON.stringify({loginId: name, password: password}),
success: function (res) {
if (res.code === 1) {
setToken(res.data);
// alert("登录成功,跳转到回调地址");
// window.location.href = getUrlParam("redirect") + "&token=" + res.data;
} else {
alert("账号密码错误");
}
}
})
}
</script>
</body>
</html>

View File

@ -0,0 +1,24 @@
function getToken() {
return window.localStorage.token || null;
}
function setToken(token) {
window.localStorage.token = token;
}
function getUserName() {
var token = getToken();
if (token == null) {
return "未登录";
} else {
var info = token.split(".")[1];
return JSON.parse(window.atob(info)).name;
}
}
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; //返回参数值
}

View File

@ -24,24 +24,10 @@
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId> <artifactId>spring-boot-starter-web</artifactId>
</dependency> </dependency>
<!--mybatis依赖 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<!--alibaba连接池依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.9</version>
</dependency>
<dependency> <dependency>
<groupId>mysql</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>mysql-connector-java</artifactId> <artifactId>spring-boot-starter-data-redis</artifactId>
<version>6.0.6</version>
</dependency> </dependency>
<dependency> <dependency>

View File

@ -1,13 +1,11 @@
package com.infinova.sso; package com.infinova.sso;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication @SpringBootApplication
@RestController @RestController
@MapperScan("com.infinova.sso.mapper")
public class SsoApplication { public class SsoApplication {
public static void main(String[] args) { public static void main(String[] args) {

View File

@ -0,0 +1,67 @@
package com.infinova.sso.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.time.Duration;
/**
* 类功能简述
* 类功能详述
*
* @author fanxb
* @date 2019/3/8 13:10
*/
@EnableCaching//开启缓存
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
/**
* 设置缓存管理器这里可以配置默认过期时间等
*
* @param connectionFactory 连接池
* @return
*/
@Bean
public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration
.defaultCacheConfig()
.entryTtl(Duration.ofSeconds(60));
RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory);
RedisCacheManager manager = new RedisCacheManager(redisCacheWriter, redisCacheConfiguration);
return manager;
}
@SuppressWarnings("all")
@Bean
public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
StringRedisTemplate template = new StringRedisTemplate(factory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
RedisSerializer stringSerializer = new StringRedisSerializer();
template.setKeySerializer(stringSerializer);
template.setValueSerializer(jackson2JsonRedisSerializer);
template.setHashKeySerializer(stringSerializer);
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}

View File

@ -0,0 +1,34 @@
package com.infinova.sso.entity;
/**
* 类功能简述
* 类功能详述
*
* @author fanxb
* @date 2019/3/7 16:46
*/
public class JwtInfo {
private String secret;
private long lastRefreshTime;
public JwtInfo(String secret, long lastRefreshTime) {
this.secret = secret;
this.lastRefreshTime = lastRefreshTime;
}
public String getSecret() {
return secret;
}
public void setSecret(String secret) {
this.secret = secret;
}
public long getLastRefreshTime() {
return lastRefreshTime;
}
public void setLastRefreshTime(long lastRefreshTime) {
this.lastRefreshTime = lastRefreshTime;
}
}

View File

@ -1,85 +1,40 @@
package com.infinova.sso.entity; package com.infinova.sso.entity;
import java.util.Date; import java.io.Serializable;
/** /**
* 类功能简述 * 类功能简述 类功能详述
* 类功能详述
* *
* @author fanxb * @author fanxb
* @date 2019/2/28 18:34 * @date 2019/2/28 18:34
*/ */
public class User { public class User implements Serializable {
private String recId; private String name;
private String userType; private String password;
private String loginId;
private String password;
private String question;
private String answer;
private Date passwordChangedDateTime;
private Date lastModDateTime;
public String getRecId() { public User() {
return recId;
}
public void setRecId(String recId) { }
this.recId = recId;
}
public String getUserType() { public User(String name, String password) {
return userType; super();
} this.name = name;
this.password = password;
}
public void setUserType(String userType) { public String getName() {
this.userType = userType; return name;
} }
public String getLoginId() { public void setName(String name) {
return loginId; this.name = name;
} }
public void setLoginId(String loginId) { public String getPassword() {
this.loginId = loginId; return password;
} }
public String getPassword() { public void setPassword(String password) {
return password; this.password = password;
} }
public void setPassword(String password) {
this.password = password;
}
public String getQuestion() {
return question;
}
public void setQuestion(String question) {
this.question = question;
}
public String getAnswer() {
return answer;
}
public void setAnswer(String answer) {
this.answer = answer;
}
public Date getPasswordChangedDateTime() {
return passwordChangedDateTime;
}
public void setPasswordChangedDateTime(Date passwordChangedDateTime) {
this.passwordChangedDateTime = passwordChangedDateTime;
}
public Date getLastModDateTime() {
return lastModDateTime;
}
public void setLastModDateTime(Date lastModDateTime) {
this.lastModDateTime = lastModDateTime;
}
} }

View File

@ -1,25 +0,0 @@
package com.infinova.sso.mapper;
import com.infinova.sso.entity.User;
import org.apache.ibatis.annotations.Select;
/**
* 类功能简述
* 类功能详述
*
* @author fanxb
* @date 2019/3/5 9:34
*/
public interface UserMapper {
/**
* Description:通过loginID获取用户信息
*
* @author fanxb
* @date 2019/3/5 9:55
* @param id
* @return com.infinova.sso.entity.User
*/
@Select("select RecID recId,LoginID loginId,Pwd password from siteviewusers where LoginID=#{id}")
User selectByLoginId(String id);
}

View File

@ -0,0 +1,180 @@
package com.infinova.sso.service;
import com.alibaba.fastjson.JSONArray;
import com.auth0.jwt.JWT;
import com.infinova.sso.entity.JwtInfo;
import com.infinova.sso.entity.User;
import com.infinova.sso.exception.CustomException;
import com.infinova.sso.util.HttpUtil;
import com.infinova.sso.util.JwtUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import javax.servlet.http.Cookie;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/**
* 类功能简述
* 类功能详述
*
* @author fanxb
* @date 2019/3/4 18:17
*/
@Service
@EnableScheduling
public class JwtService {
public static final String JWT_KEY = "jwt_token";
private Logger logger = LoggerFactory.getLogger(JwtService.class);
/**
* 存储jwt与secret对应关系
*/
private static Map<String, JwtInfo> jwtMap = new ConcurrentHashMap<>();
/**
* jwt token超时时间单位s
*/
private static final int TIME_OUT = 60 * 60;
/**
* 在此时间段内一个jwt不能重复刷新
*/
private static final int REFRESH_INTERVAL = 5 * 60 * 1000;
/**
* Description:登录获取token
*
* @param user user
* @return java.lang.String
* @author fanxb
* @date 2019/3/4 18:45
*/
public String login(User user) {
//进行登录校验
try {
if (user.getName().equalsIgnoreCase(user.getPassword())) {
String token = this.generateNewJwt(user.getName());
setCookie(token, TIME_OUT);
return token;
} else {
logger.info("账号密码错误:{}{}", user.getName(), user.getPassword());
throw new CustomException("账号密码错误");
}
} catch (Exception e) {
logger.info("账号密码错误:{},{}", user.getName(), user.getPassword());
throw new CustomException("账号密码错误");
}
}
/**
* Description:刷新token
*
* @return java.lang.String
* @author fanxb
* @date 2019/3/5 11:06
*/
public String refreshJwt(String token) {
try {
JwtInfo info = jwtMap.get(token);
Long nowTime = System.currentTimeMillis();
if (nowTime - info.getLastRefreshTime() < REFRESH_INTERVAL) {
throw new CustomException("token刷新间隔过短");
}
info.setLastRefreshTime(nowTime);
String id = JwtUtil.decode(token, info.getSecret()).get("loginId").asString();
String newToken = generateNewJwt(id);
setCookie(newToken, TIME_OUT);
return newToken;
} catch (Exception e) {
throw new CustomException(e, "token校验失败");
}
}
/**
* Description: 生成新的jwt,并放入jwtMap中
*
* @return java.lang.String
* @author fanxb
* @date 2019/3/5 10:44
*/
private String generateNewJwt(String name) {
String secret = UUID.randomUUID().toString().replaceAll("-", "");
String token = JwtUtil.encode(name, secret, TIME_OUT);
jwtMap.put(token, new JwtInfo(secret, 0));
return token;
}
/**
* Description:检查jwt有效性,返回失效jwt
*
* @return List<String> 失效jwt列表
* @author fanxb
* @date 2019/3/4 18:47
*/
public List<String> checkJwt(JSONArray tokens) {
List<String> res = new ArrayList<>();
tokens.forEach(item -> {
String jwt = (String) item;
try {
String secret = jwtMap.get(jwt).getSecret();
JwtUtil.decode(jwt, secret);
} catch (Exception e) {
e.printStackTrace();
res.add(jwt);
}
});
return res;
}
/**
* Description: 使该jwt失效
*
* @author fanxb
* @date 2019/3/4 19:58
*/
public void inValid(String jwt) {
jwtMap.remove(jwt);
setCookie("", 0);
}
/**
* Description:定时检查过期的jwt并从map中删除
*
* @author fanxb
* @date 2019/3/5 18:16
*/
@Scheduled(fixedRate = 10 * 1000)
private void cleanJwtMap() {
Date now = new Date();
Set<String> keys = jwtMap.keySet();
keys.forEach(item -> {
if (now.getTime() > JWT.decode(item).getExpiresAt().getTime()) {
jwtMap.remove(item);
logger.info("清理掉了:{}", item);
}
});
}
/**
* Description: 写入jwt token到cookie
*
* @param token token
* @param maxAge 失效时间 单位s
* @return void
* @author fanxb
* @date 2019/3/5 18:43
*/
private void setCookie(String token, int maxAge) {
Cookie cookie = new Cookie(JWT_KEY, token);
cookie.setMaxAge(maxAge);
cookie.setPath("/");
HttpUtil.getResponse().addCookie(cookie);
}
}

View File

@ -0,0 +1,66 @@
package com.infinova.sso.service;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
import com.infinova.sso.entity.User;
/**
* 类功能简述使用此类演示一些redis的缓存操作
* 加上CacheConfig注解可为当前泪下类下所有redis缓存做配置比如cacheNames给类下所有的key加上前缀
*
* @author fanxb
* @date 2019/3/8 13:53
*/
@CacheConfig(cacheNames = "redis_test")
@Service
public class RedisService {
/**
* 缓存时间首次查询后会缓存结果,key中的值可使用表达式计算
*
* @return long
*/
@Cacheable(key = "'currentTime'")
public long getTime() {
return System.currentTimeMillis();
}
@CacheEvict(key = "'currentTime'")
public void deleteTime() {
}
@Cacheable(key = "'currentTime'+#id")
public Long getTime(String id) {
return null;
}
/**
* 一般用于更新查插入操作每次都会请求db
*/
@CachePut(key = "'currentTime'+#id")
public long updateTime(String id) {
return System.currentTimeMillis();
}
/**
* 清除缓存
*
* @param id id
*/
@CacheEvict(key = "'currentTime'+#id", allEntries = false)
public void deleteTime(String id) {
}
@Caching(put = {@CachePut(value = "user", key = "'name_'+#user.name"),
@CachePut(value = "user", key = "'pass_'+#user.password")})
public User testCaching(User user) {
return user;
}
}

View File

@ -1,26 +0,0 @@
package com.infinova.sso.util;
/**
* 类功能简述 数组工具类
*
* @author fanxb
* @date 2019/3/4 17:06
*/
public class ArrayUtil {
/**
* Description: 从指定数组指定下标复制指定长度到目标数组指定下标
*
* @author fanxb
* @date 2019/3/4 17:16
* @param source 源数组
* @param sourceStart 原数组copy开始下标
* @param target 目标数组
* @param targetStart 目标数组接收开始下标
* @param length copy长度
*/
public static void copyTo(byte[] source, int sourceStart, byte[] target, int targetStart, int length) {
for (int i = 0; i < length; i++) {
target[targetStart + i] = source[sourceStart + i];
}
}
}

View File

@ -22,21 +22,20 @@ public class JwtUtil {
/** /**
* Description: 生成一个jwt字符串 * Description: 生成一个jwt字符串
* *
* @param recId 用户id * @param name 用户名
* @param loginId 登录id
* @param secret 秘钥 * @param secret 秘钥
* @param timeOut 超时时间单位s * @param timeOut 超时时间单位s
* @return java.lang.String * @return java.lang.String
* @author fanxb * @author fanxb
* @date 2019/3/4 17:26 * @date 2019/3/4 17:26
*/ */
public static String encode(String loginId, String secret, long timeOut) { public static String encode(String name, String secret, long timeOut) {
Algorithm algorithm = Algorithm.HMAC256(secret); Algorithm algorithm = Algorithm.HMAC256(secret);
String token = JWT.create() String token = JWT.create()
//设置过期时间为一个小时 //设置过期时间为一个小时
.withExpiresAt(new Date(System.currentTimeMillis() + timeOut * 1000)) .withExpiresAt(new Date(System.currentTimeMillis() + timeOut * 1000))
//设置负载 //设置负载
.withClaim("loginId", loginId) .withClaim("name", name)
.sign(algorithm); .sign(algorithm);
return token; return token;
} }
@ -46,7 +45,7 @@ public class JwtUtil {
* *
* @param token token * @param token token
* @param secret secret * @param secret secret
* @return java.util.Map<java.lang.String , com.auth0.jwt.interfaces.Claim> * @return java.util.Map<java.lang.String , com.auth0.jwt.interfaces.Claim>
* @author fanxb * @author fanxb
* @date 2019/3/4 18:14 * @date 2019/3/4 18:14
*/ */

View File

@ -1,80 +0,0 @@
package com.infinova.sso.util;
import javax.xml.bind.DatatypeConverter;
import java.security.MessageDigest;
import java.security.SecureRandom;
/**
* 类功能简述
* 类功能详述
*
* @author fanxb
* @date 2019/3/4 17:20
*/
public class PasswordUtil {
/**
* Description: plainText加salt使用sha1计算hash
*
* @param plainText 原文
* @param salt
* @return byte[]
* @author fanxb
* @date 2019/3/4 17:20
*/
private static byte[] computeHashValue(String plainText, byte[] salt) throws Exception {
byte[] plainBytes = plainText.getBytes("utf-16LE");
byte[] arr = new byte[salt.length + plainBytes.length];
MessageDigest md = MessageDigest.getInstance("SHA1");
ArrayUtil.copyTo(plainBytes, 0, arr, 0, plainBytes.length);
ArrayUtil.copyTo(salt, 0, arr, plainBytes.length, salt.length);
return md.digest(arr);
}
/**
* Description: 根据原文计算出密文,计算方法使用一个随机数做盐值和密码一起使用sha1做hash再和盐值拼接到一起
* 最后生成base64字符串
*
* @param pass 原文
* @return java.lang.String
* @author fanxb
* @date 2019/3/4 17:21
*/
public static String createPassword(String pass) throws Exception {
byte[] salt = SecureRandom.getSeed(0x10);
byte[] buffer2 = computeHashValue(pass, salt);
byte[] array = new byte[0x24];
ArrayUtil.copyTo(salt, 0, array, 0, salt.length);
ArrayUtil.copyTo(buffer2, 0, array, salt.length, salt.length);
return DatatypeConverter.printBase64Binary(array);
}
/**
* Description: 判断密文原文是否一致
*
* @param cipherPassword 密文
* @param plainPassword 原文
* @return boolean
* @author fanxb
* @date 2019/3/4 17:23
*/
public static boolean checkPassword(String cipherPassword, String plainPassword) {
try {
byte[] cipherPasswordBytes = DatatypeConverter.parseBase64Binary(cipherPassword);
byte[] saltBytes = new byte[0x10];
ArrayUtil.copyTo(cipherPasswordBytes, 0, saltBytes, 0, saltBytes.length);
byte[] passwordBytes = computeHashValue(plainPassword, saltBytes);
byte[] realPasswordBytes = new byte[20];
ArrayUtil.copyTo(cipherPasswordBytes, saltBytes.length, realPasswordBytes, 0, realPasswordBytes.length);
for (int i = 0; i < realPasswordBytes.length; i++) {
if (passwordBytes[i] != realPasswordBytes[i]) {
return false;
}
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}

View File

@ -0,0 +1,58 @@
package com.infinova.sso.util;
import com.alibaba.fastjson.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
/**
* 类功能简述
* 类功能详述
*
* @author fanxb
* @date 2019/3/8 13:26
*/
@Component
public class RedisUtil {
private static final int DEFAULT_EXPIRE_TIME = 60 * 1000;
public static RedisTemplate<String, String> redisTemplate;
@Autowired
public void setRedisTemplate(RedisTemplate<String, String> redisTemplate) {
RedisUtil.redisTemplate = redisTemplate;
}
/**
* 设置键值对使用默认过期时间
*
* @param key
* @param value
*/
public static void set(String key, Object value) {
set(key, value, DEFAULT_EXPIRE_TIME);
}
/**
* 设置键值对指定过期时间
*
* @param key key
* @param value value
* @param expireTime 过期时间
*/
public static void set(String key, Object value, long expireTime) {
redisTemplate.opsForValue().set(key, JSON.toJSONString(value));
redisTemplate.expire(key, expireTime, TimeUnit.MILLISECONDS);
}
/**
* 删除key
*
* @param key key
*/
public static void delete(String key) {
redisTemplate.delete(key);
}
}

View File

@ -5,10 +5,24 @@ server:
spring: spring:
application: application:
name: SSO name: SSO
datasource: cache:
type: com.alibaba.druid.pool.DruidDataSource type: redis
druid: redis:
driver-class-name: com.mysql.cj.jdbc.Driver database: 0
url: jdbc:mysql://localhost:3308/itoss?useUnicode=true&characterEncoding=gbk&serverTimezone=UTC&useSSL=false host: 10.82.27.177
username: root port: 6379
password: root password:
# 连接超时时间ms)
timeout: 1000ms
# 高版本springboot中使用jedis或者lettuce
jedis:
pool:
# 连接池最大连接数(负值表示无限制)
max-active: 8
# 连接池最大阻塞等待时间(负值无限制)
max-wait: 5000ms
# 最大空闲链接数
max-idle: 8
# 最小空闲链接数
min-idle: 0

View File

@ -4,7 +4,6 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>认证中心</title> <title>认证中心</title>
</head> </head>
<body onload="steal()">
<div style="text-align: center;">这里是认证中心主页</div> <div style="text-align: center;">这里是认证中心主页</div>
<div> <div>
<button onclick="clearToken()">清除token</button> <button onclick="clearToken()">清除token</button>

View File

@ -1,16 +1,12 @@
package com.infinova.sso.service_test; package com.infinova.sso.service_test;
import com.infinova.sso.entity.User;
import com.infinova.sso.service.JwtService; import com.infinova.sso.service.JwtService;
import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.context.junit4.SpringRunner;
import javax.xml.bind.DatatypeConverter;
/** /**
* 类功能简述 * 类功能简述
* 类功能详述 * 类功能详述
@ -28,11 +24,6 @@ public class JwtServiceTest {
@Test @Test
public void loginTest() throws Exception { public void loginTest() throws Exception {
User user = new User();
user.setLoginId("admin");
user.setPassword(DatatypeConverter.printBase64Binary("manage".getBytes("utf-8")));
String token = jwtService.login(user);
Assert.assertTrue(token != null && token.length() > 0);
} }
} }

View File

@ -0,0 +1,60 @@
package com.infinova.sso.service_test;
import com.infinova.sso.entity.User;
import com.infinova.sso.service.RedisService;
import com.infinova.sso.util.RedisUtil;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
/**
* 类功能简述 类功能详述
*
* @author fanxb
* @date 2019/3/8 14:31
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class RedisServiceTest {
private Logger logger = LoggerFactory.getLogger(RedisService.class);
@Autowired
private RedisService redisService;
@Autowired
private RedisUtil redisUtil;
@Test
public void getTimeTest() throws Exception {
logger.info("时间为:{}", redisService.getTime());
Thread.sleep(1000);
logger.info("时间为:{}", redisService.getTime());
Thread.sleep(1000);
logger.info("时间为:{}", redisService.getTime());
redisService.deleteTime();
Thread.sleep(1000);
logger.info("时间为:{}", redisService.getTime());
}
@Test
public void getTimeIdTest() throws Exception {
logger.info("缓存时间:{}", redisService.updateTime("1"));
Thread.sleep(1000);
logger.info("1s后取数据{}", redisService.getTime("1"));
Thread.sleep(1000);
logger.info("1s后更新时间{}", redisService.updateTime("1"));
Thread.sleep(1000);
logger.info("1s后取数据{}", redisService.getTime("1"));
RedisUtil.set("test1", "test1", 100000);
}
@Test
public void testCaching() throws Exception {
User user = new User("aaa","bbb");
redisService.testCaching(user);
}
}