简介
单点登录SSO(Single Sign On)是在一个多系统共存的环境下,用户在一处登录之后,就不用在其他的系统中登录,也就是用户的一次登录能得到其他所有系统的信任.单点登录在大型网站里面使用的比较多,例如像阿里巴巴这样的网站,在万丈的背后是成百上千的子系统,用户一次操作或交易可能涉及到几个十几个子系统的协作,如果每个子系统都需要用户认证,会在无形中增加时间的耗费
spring:
redis:
database: 0 #redis的默认数据库为0
host: 139.224.245.96 #链接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://139.224.245.96:3306/huibo?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
show-sql: true
server:
port: 8989
REDIS_KEY : uuuu
实体类user
package com.example.demo.pojo;
import lombok.Data;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
@Data
@Entity
@Table(name = "user")
public class user {
@Id
@Column(name = "id",unique = true,nullable = false)
private int id;
private String name;
private int password;
}
dao层
package com.example.demo.dao;
import com.example.demo.pojo.user;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface UserDao extends JpaRepository<user,Integer> {
public user findByNameAndAndPassword(String username,int password);
}
service层
package com.example.demo.service;
import com.example.demo.dao.UserDao;
import com.example.demo.pojo.user;
import com.example.demo.redis.JedisDao;
import com.example.demo.util.CookieUtils;
import com.example.demo.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 UserService {
@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.randomAlphabetic(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.findByNameAndAndPassword(u.getName(),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;
}
}
controller层
package com.example.demo.controller;
import com.example.demo.pojo.user;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;
@Controller
public class usercontroller {
@Autowired
private UserService 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;
}
}
}
redis类
package com.example.demo.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);
}
package com.example.demo.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;
}
}
util工具类
package com.example.demo.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;
}
}
package com.example.demo.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;
}
}
package com.example.demo.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字符串。
* Title: pojoToJson
* Description:
* @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
* Title: jsonToList
* Description:
* @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;
}
}
package com.example.demo.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;
}
}
前端登入成功页面
<!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>
登入页面
<!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="name" 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>
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.directory.studio/org.apache.commons.lang -->
<dependency>
<groupId>org.apache.directory.studio</groupId>
<artifactId>org.apache.commons.lang</artifactId>
<version>2.6</version>
</dependency>
<!--引入thymeleaf-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>