java单点登录 session_Session共享方法以及单点登录方案

1.两个服务器通过同步session实现session共享

f2f8d1f99d6f689610e61b5684710520.png

优点:配置简单

缺点:如果机器多了,就会出现大量的网络传输,甚至容易引起网络风暴,导致系统崩溃,只能适合少数的机器。

2.将session存储在某个介质上、比如数据库上或者缓存服务器上,进行统一管理。

d9547f651bc8f42b0b26efc9f82d2740.png

下面是一个springboot+springSession+redis共享的列子

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

4.0.0

com.sumei

login

0.0.1-SNAPSHOT

jar

login

Demo project for Spring Boot

org.springframework.boot

spring-boot-starter-parent

1.5.10.RELEASE

UTF-8

UTF-8

1.8

org.springframework.boot

spring-boot-starter-data-redis

org.springframework.session

spring-session-data-redis

org.springframework.boot

spring-boot-starter-web

org.springframework.session

spring-session

org.springframework.boot

spring-boot-starter-test

test

org.springframework.boot

spring-boot-maven-plugin

spring-milestone

https://repo.spring.io/libs-release

package com.sumei.login;

import org.springframework.session.web.http.DefaultCookieSerializer;

import javax.servlet.http.HttpServletRequest;

/**

* 自定义CookiePath

*/

public class CustomerCookiesSerializer extends DefaultCookieSerializer {

private String getCookiePath(HttpServletRequest request) {

return "/";

}

}

package com.sumei.login;

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.CookieHttpSessionStrategy;

@Configuration

@EnableRedisHttpSession

public class Config {

/**

*jedis简单配置

* @return

*/

@Bean

public JedisConnectionFactory connectionFactory() {

JedisConnectionFactory connectionFactory = new JedisConnectionFactory();

connectionFactory.setPort(6379);

connectionFactory.setHostName("192.168.31.100");

return connectionFactory;

}

/**

*CookieHttpSessionStrategy 配置

* @return

*/

@Bean

public CookieHttpSessionStrategy cookieHttpSessionStrategy(){

CookieHttpSessionStrategy cookieHttpSessionStrategy=new CookieHttpSessionStrategy();

CustomerCookiesSerializer cookiesSerializer= new CustomerCookiesSerializer();

cookiesSerializer.setDomainName("sumei.com");

cookieHttpSessionStrategy.setCookieSerializer(cookiesSerializer);

return cookieHttpSessionStrategy;

}

}

package com.sumei.login;

import org.springframework.session.web.context.AbstractHttpSessionApplicationInitializer;

public class Initializer extends AbstractHttpSessionApplicationInitializer {

public Initializer() {

super(Config.class);

}

}

package com.sumei.login;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication

@ComponentScan

public class LoginApplication {

public static void main(String[] args) {

SpringApplication.run(LoginApplication.class, args);

}

}

package com.sumei.login;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpSession;

import java.util.HashMap;

import java.util.Map;

/**

*测试类

*/

@RestController

public class LoginController {

@RequestMapping("test1")

public Map getSessionId(HttpServletRequest request){

HttpSession session = request.getSession(false);

String session_id=null;

if(session==null){

session=request.getSession(true);

}

session_id = session.getId();

System.out.println(session_id);

Map res=new HashMap<>();

res.put("sessionid",session_id);

if(session.getAttribute("boot")==null){

System.out.println("***********************");

session.setAttribute("boot","nbbo");

}else {

System.out.println(session.getAttribute("boot"));

}

return res;

}

}

将其打成jar放到服务器上进行测试

配置我本地的host 配置文件

192.168.31.100 top.sumei.com

192.168.31.101 bottom.sumei.com

用 java -jar login-0.0.1-SNAPSHOT.jar启动服务 浏览器地址

ac99d38bde15cf80570baa6bfd3e9b9c.png

9d5c52ea13db86acad2cf311e9b7b94e.png

发现 top.sumei.com 与  bottom.sumei.com 的sesionid 是一样的,说明session共享成功。

3.基于JWT(JSON WEB TOKEN)代替的方案

f2dc67407ac6d3b51e9efc1bf2f0db10.png

jws 相比Cookie的优势

支持跨域跨站点访问:

Cookie是不允许垮域访问的,可以通过设置顶级域名的方式实现部分跨域,但是跨站点的访问仍然不支持,

如果使用Token机制,就可以通过HTTP头传输用户认证信息,从而更好的实现跨域跨站点。

无状态:

Token机制在服务端不需要存储session信息,Token自身包含了登录用户的信息,只需要在客户端的cookie或本地介质存储状态信息;

更适用于移动应用:

当客户端是原生应用时,Cookie是不被支持的,虽然目前Webview的方式可以解决Cookie问题,

但是显然采用Token认证机制会简单得多;

安全性更强:

因为不再依赖于Cookie,所以你就不需要考虑对CSRF(跨站请求伪造)的防范;

标准化易扩展:

可以采用标准化的 JSON Web Token (JWT),对以后系统接入Node等纯前端开发更便捷;

相比Session一致性提高性能:

相比服务端保存Session一致性信息,并查询用户登录状态,一般来说Token的验证过程(包含加密和解密),性能开销会更小。

JWS 由三部分组成(header,payload,Signature)

header {

"alg": "HS256", //加密算法

"typ": "JWT"      //令牌类型

}

payload{

{"iss",value},//签发者

{"iat", value},//非必须。issued at。 token创建时间,unix时间戳格式

{"exp", value},//过期时间

{"aud", value},//非必须。接收该JWT的一方。

{"sub", value},//拥有者

{"jti", value},//非必须。JWT ID。针对当前token的唯一标识

//自定义claims

{"user",value}

{"passwd",value}

..........

};

signature 就是用点号将header和payload联系起来,然后用header里面指定的加密方法进行加密后的字符串。

一个简单的测试demo

package com.sumei.login.jwt;

public class JSONTokenInfo {

/**

* 过期时间

*/

private String uid;

/**

* 用户id

*/

private int exprie;

public JSONTokenInfo() {

}

public JSONTokenInfo(String uid) {

this.uid = uid;

}

public String getUid() {

return uid;

}

public void setUid(String uid) {

this.uid = uid;

}

public int getExprie() {

return exprie;

}

public void setExprie(int exprie) {

this.exprie = exprie;

}

}

package com.sumei.login.jwt;

import io.jsonwebtoken.Claims;

import io.jsonwebtoken.Jws;

import io.jsonwebtoken.Jwts;

import io.jsonwebtoken.SignatureAlgorithm;

import org.joda.time.DateTime;

import javax.crypto.spec.SecretKeySpec;

import javax.xml.bind.DatatypeConverter;

import java.security.Key;

public class JWSTokenUtil {

private static String jwt_key_user_id="uid";

/**

* 生成一个加密key

* @return

*/

public static Key getKey(){

SignatureAlgorithm es256 = SignatureAlgorithm.HS256;

byte[] bytes= DatatypeConverter.parseBase64Binary("secret key");

SecretKeySpec secretKeySpec = new SecretKeySpec(bytes,es256.getJcaName());

return secretKeySpec;

}

/**

* 生成token

* @param jsonTokenInfo

* @param exprie

* @return

*/

public static String getToken(JSONTokenInfo jsonTokenInfo,int exprie){

return Jwts.builder().claim(jwt_key_user_id,jsonTokenInfo)

.setExpiration(DateTime.now().plusSeconds(exprie).toDate())

.signWith(SignatureAlgorithm.HS256,getKey()).compact();

}

/**

*

* @param token

* @return

*/

public static JSONTokenInfo getInstance(String token) {

Jws claimsJws = Jwts.parser().setSigningKey(getKey()).parseClaimsJws(token);

Claims body = claimsJws.getBody();

JSONTokenInfo jsonTokenInfo=new JSONTokenInfo();

jsonTokenInfo.setUid(body.get(jwt_key_user_id).toString());

return jsonTokenInfo;

}

}

package com.sumei.login;

import com.sumei.login.jwt.JSONTokenInfo;

import com.sumei.login.jwt.JWSTokenUtil;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import javax.servlet.http.HttpSession;

import java.util.HashMap;

import java.util.Map;

@RestController

public class JWSTokenController {

/**

*

* @param uid

* @param response

* @return

*/

@RequestMapping("testJws")

public String testJws(String uid,HttpServletResponse response){

JSONTokenInfo jsonTokenInfo=new JSONTokenInfo(uid);

String token = JWSTokenUtil.getToken(jsonTokenInfo, 3000);

response.addHeader("Set-Cookie","access_token="+token+"PATH=/;HttpOnly");

System.out.println(token);

return token;

}

/**

* 根据token检查uuid

* @param token

* @return

*/

@RequestMapping("testToken")

public JSONTokenInfo testToken(String token){

JSONTokenInfo jsonTokenInfo = JWSTokenUtil.getInstance(token);

return jsonTokenInfo;

}

}

打成jar 进行本地测试

启动java -jar ***.jar 启动两个服务 一个端口为8888 一个端口为8881

1.浏览器输入 http://localhost:8888/testJws?uid=001

41b3fd2367131bab8b2953a6bea76796.png

2.复制token 将这个token 传递给8881的端口。

在浏览器输入 http://localhost:8881/testToken?token=eyJhbGciOiJIUzI1NiJ9.eyJ1aWQiOnsidWlkIjoiMDAxIiwiZXhwcmllIjowfSwiZXhwIjoxNTIxMzY2OTkxfQ.FSfsjldW7jr8TNHlfREu6l_nDPQQ33LdvMydem3ZSas

84b1a19ee81ee2ac028f49d6d234f048.png

在8881中我并没有用浏览器传入uid=1 说明通过这种方式服务之间可以进行共享数据,可以解决单点登录。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值