springdatajpa+Redis实现单点登录(sso)
项目结构
实体类
package com.data.pojo;
import lombok.Data;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
/**
* Created by Administrator on 2019/11/18.
*/
@Data
@Entity
@Table(name = "user")
public class User {
@Id
@Column(name = "id",unique = true,nullable = false)
private int id;
@Column(name = "username",nullable = false)
private String username;
@Column(name = "password",nullable = false)
private String password;
}
dao层
package com.data.dao;
import com.data.pojo.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
/**
* Created by Administrator on 2019/11/18.
*/
@Repository
public interface UserDao extends JpaRepository<User,Integer> {
public User findByUsernameAndPassword(String username,String password);
}
redis 层
jedisdao
package com.data.redis;
public interface JedisDao {
//查
public String getValue(String key);
//删
public Long delValue(String key);
//增
public String setValue(String key, String value);
//设置时间
public Long expire(String key, int seconds);
}
JedisDaoImpl
package com.data.redis;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
@Component
public class JedisDaoImpl implements JedisDao{
//连接池
@Autowired
private JedisPool jedisPool;
@Override
public String getValue(String key) {
Jedis jedis = jedisPool.getResource();
String value = jedis.get(key);
jedis.close();
return value;
}
@Override
public Long delValue(String key) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.del(key);
jedis.close();
return result;
}
@Override
public String setValue(String key, String value) {
Jedis jedis = jedisPool.getResource();
String str = jedis.set(key, value);
jedis.close();
return str;
}
@Override
public Long expire(String key,int seconds) {
Jedis jedis = jedisPool.getResource();
Long time = jedis.expire(key, seconds);
jedis.close();
return time;
}
}
service层
package com.data.service;
import com.data.dao.UserDao;
import com.data.pojo.User;
import com.data.redis.JedisDao;
import com.data.util.CookieUtils;
import com.data.util.JsonUtils;
import org.apache.commons.lang.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@Service
public class UserServiceImpl{
@Autowired
private UserDao userDao;
@Autowired
private JedisDao jedisDao;
@Value("${REDIS_KEY}") //从配置文件中取值
private String REDIS_KEY;
private Map<Integer,String> userInfo = new HashMap<>();
public Object getall(){
String s= RandomStringUtils.randomAlphanumeric(10);
if (jedisDao.getValue(s)!=null){
return jedisDao.getValue(s);
}else{
List<User>userList= userDao.findAll();
jedisDao.setValue(s,JsonUtils.objectToJson(userList));
return userList;
}
}
public User userlogin(HttpServletRequest request, HttpServletResponse response, User u){
//先进行数据库查询一遍
User us=userDao.findByUsernameAndPassword(u.getUsername(),u.getPassword());
//判断us是否为空
if(us==null){
return null;
}
//定义新的token
String token="user_"+ UUID.randomUUID().toString();
//判断map中是否存在该id
if(!ObjectUtils.isEmpty(userInfo.get(us.getId()))){
//从map中获得redis中的key
String oldToken=userInfo.get(us.getId());
//删除redis中老的值
jedisDao.delValue(oldToken);
}
//将新的的key保存到map中
userInfo.put(us.getId(),token);
//将信息存入redis
jedisDao.setValue(token,JsonUtils.objectToJson(us));
//设置redis信息过期时间
// redisTemplate.expire(token,5*60, TimeUnit.MILLISECONDS);
//将token放入cookie中
CookieUtils.setCookie(request,response,"USER_TOKEN",token,5*60,true);
return us;
}
public String getUserByToken(HttpServletResponse response, HttpServletRequest request) {
User us=null;
//从cookie中取出用户token
String token=CookieUtils.getCookieValue(request,"USER_TOKEN");
String s = jedisDao.getValue(token);
return s;
}
}
util工具类
CookieUtils
package com.data.util;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
/**
*
* Cookie 工具类
*
*/
public final class CookieUtils {
/**
* 得到Cookie的值, 不编码
*
* @param request
* @param cookieName
* @return
*/
public static String getCookieValue(HttpServletRequest request, String cookieName) {
return getCookieValue(request, cookieName, false);
}
/**
* 得到Cookie的值,
*
* @param request
* @param cookieName
* @return
*/
public static String getCookieValue(HttpServletRequest request, String cookieName, boolean isDecoder) {
Cookie[] cookieList = request.getCookies();
if (cookieList == null || cookieName == null) {
return null;
}
String retValue = null;
try {
for (int i = 0; i < cookieList.length; i++) {
if (cookieList[i].getName().equals(cookieName)) {
if (isDecoder) {
retValue = URLDecoder.decode(cookieList[i].getValue(), "UTF-8");
} else {
retValue = cookieList[i].getValue();
}
break;
}
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return retValue;
}
/**
* 得到Cookie的值,
*
* @param request
* @param cookieName
* @return
*/
public static String getCookieValue(HttpServletRequest request, String cookieName, String encodeString) {
Cookie[] cookieList = request.getCookies();
if (cookieList == null || cookieName == null) {
return null;
}
String retValue = null;
try {
for (int i = 0; i < cookieList.length; i++) {
if (cookieList[i].getName().equals(cookieName)) {
retValue = URLDecoder.decode(cookieList[i].getValue(), encodeString);
break;
}
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return retValue;
}
/**
* 设置Cookie的值 不设置生效时间默认浏览器关闭即失效,也不编码
*/
public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
String cookieValue) {
setCookie(request, response, cookieName, cookieValue, -1);
}
/**
* 设置Cookie的值 在指定时间内生效,但不编码
*/
public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
String cookieValue, int cookieMaxage) {
setCookie(request, response, cookieName, cookieValue, cookieMaxage, false);
}
/**
* 设置Cookie的值 不设置生效时间,但编码
*/
public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
String cookieValue, boolean isEncode) {
setCookie(request, response, cookieName, cookieValue, -1, isEncode);
}
/**
* 设置Cookie的值 在指定时间内生效, 编码参数
*/
public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
String cookieValue, int cookieMaxage, boolean isEncode) {
doSetCookie(request, response, cookieName, cookieValue, cookieMaxage, isEncode);
}
/**
* 设置Cookie的值 在指定时间内生效, 编码参数(指定编码)
*/
public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
String cookieValue, int cookieMaxage, String encodeString) {
doSetCookie(request, response, cookieName, cookieValue, cookieMaxage, encodeString);
}
/**
* 删除Cookie带cookie域名
*/
public static void deleteCookie(HttpServletRequest request, HttpServletResponse response,
String cookieName) {
doSetCookie(request, response, cookieName, "", -1, false);
}
/**
* 设置Cookie的值,并使其在指定时间内生效
*
* @param cookieMaxage cookie生效的最大秒数
*/
private static final void doSetCookie(HttpServletRequest request, HttpServletResponse response,
String cookieName, String cookieValue, int cookieMaxage, boolean isEncode) {
try {
if (cookieValue == null) {
cookieValue = "";
} else if (isEncode) {
cookieValue = URLEncoder.encode(cookieValue, "utf-8");
}
Cookie cookie = new Cookie(cookieName, cookieValue);
if (cookieMaxage > 0)
cookie.setMaxAge(cookieMaxage);
if (null != request) {// 设置域名的cookie
String domainName = getDomainName(request);
System.out.println(domainName);
if (!"localhost".equals(domainName)) {
//cookie.setDomain(domainName);
}
}
cookie.setPath("/");
response.addCookie(cookie);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 设置Cookie的值,并使其在指定时间内生效
*
* @param cookieMaxage cookie生效的最大秒数
*/
private static final void doSetCookie(HttpServletRequest request, HttpServletResponse response,
String cookieName, String cookieValue, int cookieMaxage, String encodeString) {
try {
if (cookieValue == null) {
cookieValue = "";
} else {
cookieValue = URLEncoder.encode(cookieValue, encodeString);
}
Cookie cookie = new Cookie(cookieName, cookieValue);
if (cookieMaxage > 0)
cookie.setMaxAge(cookieMaxage);
if (null != request) {// 设置域名的cookie
String domainName = getDomainName(request);
System.out.println(domainName);
if (!"localhost".equals(domainName)) {
//本地测试的时候不要写.实际发布时在打开
//cookie.setDomain(domainName);
}
}
cookie.setPath("/");
response.addCookie(cookie);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 得到cookie的域名
*/
private static final String getDomainName(HttpServletRequest request) {
String domainName = null;
String serverName = request.getRequestURL().toString();
if (serverName == null || serverName.equals("")) {
domainName = "";
} else {
final int end = serverName.lastIndexOf("/");
serverName = serverName.substring(0, end);
final String[] domains = serverName.split("\\.");
int len = domains.length;
if (len > 3) {
// www.xxx.com.cn
domainName = "." + domains[len - 3] + "." + domains[len - 2] + "." + domains[len - 1];
} else if (len <= 3 && len > 1) {
// xxx.com or xxx.cn
domainName = "." + domains[len - 2] + "." + domains[len - 1];
} else {
domainName = serverName;
}
}
if (domainName != null && domainName.indexOf(":") > 0) {
String[] ary = domainName.split("\\:");
domainName = ary[0];
}
return domainName;
}
}
JedisUtil
package com.data.util;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.JedisPool;
@Configuration
//链接redis 获取appliaction.yml 里的数据以spring.redis开头的方式
@ConfigurationProperties(prefix = "spring.redis")
public class JedisUtil {
//属性名字和配置文件中必须一致,还要提供get和set方法
private String host; //读取到spring.redis.hostg.redis.port
private int port;//sprin
@Bean
public JedisPool jedisPool(){
JedisPool jedisPool = new JedisPool(host,port);
System.out.println("已连接:"+host+"上的redis,端口号为:"+port);
return jedisPool;
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
}
JsonUtils
package com.data.util;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.List;
public class JsonUtils {
// 定义jackson对象
private static final ObjectMapper MAPPER = new ObjectMapper();
/**
* 将对象转换成json字符串。
* <p>Title: pojoToJson</p>
* <p>Description: </p>
* @param data
* @return
*/
public static String objectToJson(Object data) {
try {
String string = MAPPER.writeValueAsString(data);
return string;
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
/**
* 将json结果集转化为对象
*
* @param jsonData json数据
* @param class 对象中的object类型
* @return
*/
public static <T> T jsonToPojo(String jsonData, Class<T> beanType) {
try {
T t = MAPPER.readValue(jsonData, beanType);
return t;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 将json数据转换成pojo对象list
* <p>Title: jsonToList</p>
* <p>Description: </p>
* @param jsonData
* @param beanType
* @return
*/
public static <T>List<T> jsonToList(String jsonData, Class<T> beanType) {
JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType);
try {
List<T> list = MAPPER.readValue(jsonData, javaType);
return list;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
SimpleResponse
package com.data.util;
/**
* 自定义响应类
* @author lt
*/
public class SimpleResponse {
private boolean success;
private Object data;
private String errCode;
private String errMsg;
private String errDesc;
public SimpleResponse(Object data) {
this.data = data;
this.success=true;
}
public SimpleResponse(boolean success) {
this.success = success;
}
public SimpleResponse(String errCode, String errMsg, String errDesc) {
this.errCode = errCode;
this.errMsg = errMsg;
this.errDesc = errDesc;
this.success=false;
}
public static SimpleResponse success(boolean success){
return new SimpleResponse(success);
}
public static SimpleResponse success(Object data){
return new SimpleResponse(data);
}
public static SimpleResponse error(String errCode, String errMsg, String errDesc){
return new SimpleResponse(errCode,errMsg,errDesc);
}
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public String getErrCode() {
return errCode;
}
public void setErrCode(String errCode) {
this.errCode = errCode;
}
public String getErrMsg() {
return errMsg;
}
public void setErrMsg(String errMsg) {
this.errMsg = errMsg;
}
public String getErrDesc() {
return errDesc;
}
public void setErrDesc(String errDesc) {
this.errDesc = errDesc;
}
}
application.yml
spring:
redis:
database: 0 #redis的默认数据库为0
host: 120.77.223.242 #链接redis的ip
port: 6379 #链接redis的端口号
password: #链接redis的密码 默认为空
jedis:
pool:
max-total: 200 #链接redis的总数目
max-active: 100 #链接redis的最大
max-idle: 8 #最大的链接数量
min-idle: 5 #最小的链接数量
datasource:
url: jdbc:mysql://120.77.223.242:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
jpa:
show-sql: true
server:
port: 8989
REDIS_KEY : uuuu
登录页面
login
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<center>
<p>登录页面</p>
<form method="POST" action="doLogin.html">
<p><label>用户名:</label><input type="text" name="username" id="username"></p>
<p><label>密码:</label><input type="password" name="password" id="password"></p>
<p><input type="submit" style="color: blue"> <input type="reset"></p>
<p><span th:text="${error}"></span></p>
</form>
</center>
</body>
</html>
index
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>欢迎</h1>
</body>
<script th:src="@{/js/jquery-1.12.4.js}"></script>
<script type="text/javascript">
$(function () {
$.get("/info",function (data) {
if(data.msg==false){
alert("您的账号已经在别处登录!");
location.href="/login";
}
})
})
</script>
</html>
数据库
/*
Navicat Premium Data Transfer
Source Server : 120.77.223.242
Source Server Type : MySQL
Source Server Version : 80018
Source Host : 120.77.223.242:3306
Source Schema : test
Target Server Type : MySQL
Target Server Version : 80018
File Encoding : 65001
Date: 25/11/2019 16:43:18
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (1, '何城东', '123');
SET FOREIGN_KEY_CHECKS = 1;
controller层
package com.data.controller;
import com.data.pojo.User;
import com.data.service.UserServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Controller
public class testredis {
@Autowired
private UserServiceImpl userService;
@RequestMapping("/getall")
@ResponseBody
public Object getall(){
return userService.getall();
}
@GetMapping(value = "/login")
public String login1(){
return "login";
}
@GetMapping(value = "/success")
public String success(){
return "index";
}
@PostMapping("/doLogin.html")
public String login(HttpServletResponse response , HttpServletRequest request, User us, Model model){
try{
User u = userService.userlogin(request, response, us);
if(u==null){
model.addAttribute("error","用户名或密码不匹配");
return "login";
}
return "redirect:/success";
}catch (Exception e){
e.printStackTrace();
model.addAttribute("error","用户名或密码不匹配");
return "login";
}
}
@GetMapping("/info")
@ResponseBody
public Map getUserInfo(HttpServletResponse response , HttpServletRequest request) throws Exception {
Map<Object,Object> map=new HashMap<>();
try{
String s = userService.getUserByToken(response, request);
if(s!=null){
map.put("msg",true);
}else{
map.put("msg",false);
}
return map;
}catch (Exception e){
map.put("success","根据token获取用户信息失败");
return map;
}
}
}
实现效果