多点登陆 token 刷新_单点登陆(sso)

668325442e484a33c70aa00aad2fe7e5.png

有状态登陆(cookie+redis)

首先有一个建立一个responseBean的类,两个属性,状态码和存储的数据。

首先是登陆:

①controller调用相应的服务(service)通过用户输入的账号和密码到数据库进行查询

②如果没有则直接向controller返回一个状态码为404,数据为空的responsebean对象

③有的话,将对象存在redis中,key得包含一个uuid的信息,比如key为user:toke:uuid,存的值为查出来的用户对象(一般新建一个用户对象,只存用户名,不用存密码),设置一个有效期。

④向controller返回一个状态码为200,数据为uuid的responseBean对象。

⑤controller判断拿到的response对象。如果是404,则向客户端回复用户名或则密码错误,如果是200,那么new一个cookie,key可以为user-token,值为拿到的responseBean对象里边的uuid。

注意点:redis缓存存储登陆的对象,要设置有效期,一般时间为30分钟,controller设置cookie的时候,要注意以下

if(200){
    Cookie cookie =new Cookie("user-token", (String) login.getData());
    cookie.setPath("/");
    cookie.setHttpOnly(true);
    cookie.setDomain("**.com"); 
    response.addCookie(cookie);
}

其中:cookie.setPath("/");可以被同一个cookie应用服务器的其他应用访问。setHttpOnly(true),这样设置后js脚本将无法读取到cookie信息,有效防止XSS攻击(Cross Site Scripting跨站脚本攻击);setDomain();解决跨域的问题,一般设为父域名,然后下面的所有子域名都能访问。

查看登陆状态

@RequestMapping("login_status")
    @CrossOrigin(origins = "*",allowCredentials = "true")
    @ResponseBody
    public ResponseBean checkLogin(@CookieValue(name = "user-token",required = false) String uuid){

        //先判断客户端是否传cookie,有则去redis查看是否过期,没有过期,刷新生存时间,返回对象,否则算是没有登陆
        if ((uuid!=null)) {
            return userService.checkLogin(uuid);
        }
        return new ResponseBean("404", null);
    }

首先判断是否携带"user-token"的cookie,没有的话,则没有登陆,有的话拿到uuid,调用service的相关方法查看"user:token:uuid"的key是否过期,过期则没有登陆,没有过期,则刷新有效期为30分钟,将user对象的相关信息返回给controller。

注销登陆:

controller拿到客户端传过来的uuid,通过uuid直接删除cookie

Cookie cookie=new Cookie("user-token", uuid);
            cookie.setDomain("**.com");
            cookie.setPath("/");
            cookie.setHttpOnly(true);
            cookie.setMaxAge(0);
            response.addCookie(cookie);
            return new ResponseBean("200", "成功");

同源策略的问题:(协议、域名、端口一致)

问题,在首页系统,获取登陆认证状态,因为首页系统和sso系统是两个系统,如果这样写,请求能发出到登陆系统,但是收不到回应,因为ajax无法访问跨域的资源,基于同源策略的。

   $.ajax({
            url:"http://sso.**.com:9096/user/login_status",
            success:function (data) {
                if(data.statusCode==200){
                    alert("已登录")
                }
            }
        })

解决办法1:jsonp

客户端页面

<script type="text/javascript">
    function deal(data){
        console.log(data);
    }
</script>
<!--jsonp-->
<script src="http://sso.**.com:9096/user/login_status?callback=deal"></script>

服务端:

@RequestMapping("login_status")
@ResponseBody
public String checkIsLoginJsonp(@CookieValue(name = "user_token",required = false) String uuid,
                                String callback) throws JsonProcessingException {

    ResultBean resultBean = null;
    if(uuid != null){
        resultBean = userService.checkIsLogin(uuid);
    }else{
        //3.返回找不到的结果
        resultBean = new ResultBean("404", null);
    }
    //将对象转换为json
    ObjectMapper objectMapper = new ObjectMapper();
    String json = objectMapper.writeValueAsString(resultBean);
    //回调客户端的方法
    return callback+"("+json+")";//deal(json) padding
}

客户端的另一种编写方式,此时服务端不要做任何改变。

//那么当从服务器接收到数据时,实际上是用了&lt;script&gt;标签而不是XMLHttpRequest对象。
$.ajax({
    url:"http://sso.**.com:9096/user/login_status",
    jsonp:"callback",
    jsonpCallback:"deal",
    dataType:"jsonp"
})

此时不再是XmlHttpRequest对象了 ,仍然是script标签。


另一种,通过ajax(xhr)实现跨域。客户端的编写

$.ajax({
    url:"http://sso.**.com:9096/user/login_status",
    crossDomain:true,
    xhrFields:{withCredentials:true},
    success:function (data) {
        console.log(data);
    }
})

服务端的编写

@CrossOrigin(origins = "*",allowCredentials = "true")

注意

  1. crossDomain 跨域
  2. 跨源请求默认不提供凭据(cookie、HTTP认证及客户端SSL证明等),通过设置withCredentials:true,可以实现携带cookie等信息。
  3. springmvc 4.2以上版本支持 @CrossOrigin 注解,实现跨域,allowCredentials指的是接收cookie的凭据参数。

无状态登录(cookie+jwt)

JSON Web Token是什么?

https://jwt.io/introduction/

官网描述:jwt是一套开放的标准(RFC 7519),它定制了一套简洁且URL安全的方案,以安全地在客户端和服务器端传输JSON格式的信息。

JWT格式

jwt有三个部分组成,Header,Payload,和Signature,格式为:header.Payload.Signature.

Header

header:{ 
"typ":"JWT", 
"alg":"HS256" 
}

header存放的内容说明编码对象时一个JWT和使用“SHA-256”的算法进行加密,加密生成Signature.

Claim(编码之后得到Payload)

{ 
"iss":"Issuer —— 用于说明该JWT是由谁签发的", 
"sub":"Subject —— 用于说明该JWT面向的对象", 
"aud":"Audience —— 用于说明该JWT发送给的用户", 
"exp":"Expiration Time —— 数字类型,说明该JWT过期的时间", 
"nbf":"Not Before —— 数字类型,说明在该时间之前JWT不能被接受与处理", 
"iat":"Issued At —— 数字类型,说明该JWT何时被签发", 
"jti":"JWT ID —— 说明标明JWT的唯一ID", 
"user-definde1":"自定义属性举例", 
"user-definde2":"自定义属性举例" 
} 

claim里边的都是可选的。里边可以存放一些自定义属性,在用户认证用于表明一个用户的身份,claim经过Base64编码得到Payload。

Signature

用上面定义的算法一个存放在服务端的密钥对Header.Payload进行加密,得到Signature.

服务端验证

客户端将token通过cookie到达服务端,服务端会对Header进行解码得到加密的算法,然后通过存放在服务器端的密钥对Headler.Payload这个字符串进行加密,对比JWT中的Signature以验证token是否有效,完成身份的验证,通过验证才会使用payload的数据。

登陆验证流程

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值