基于JWT实现单点登录

单点登录概述:
多系统共存下,用户在一处地方登录,得到其他所有系统的信任,无需再次登录。

自己的理解:在前端用户点击登录触发后端登录接口,登录成功的时候,后端jwt生成一个token,后端将token返给前端,前端把token放进需要进行验证的接口的请求头(header)中去,用户带着这个token去进行验证。(token设置过期时间),验证成功则拦截器放行,否则拦截

这里介绍一些jwt基本概念

JWT:
1.认证流程
a.首先,前端通过web表单将自己的用户民和密码发送到后端的接口,这一过程一般是一个HTTP,POST请求。建议的方式是通过SSL
加密的方式传输(https协议),从而避免敏感信息被嗅探。
b.后端核对用户名和密码成功后,将用户的id等其他信息作为JWT Payload(负载),将其与头部分别进行Base64编码拼接后签名,形成
一个JWT(token),形成的JWT就是一个形同111.zzz.xxx的字符串, token,head ,payload, singurater
c.后端将JWT字符串 作为登录成功的返回结果返回给前端,前端可以返回的结果保存在localStorage 或sessionStorage上,退出登录
时前端删除保存的JWT即可。
d.前端在每次请求时将JWT放入HTTP Header中的Authoriztion 位。(放在Header中的原因是解决XSS和XSRF问题) HEADER.
e.后端检查是否存在,如存在验证JWT的有效性。例如,检查签名是否正确;检查Token是否过期;检查Token的接收方是否是自己(可选)
f。验证通过后,后端使用JWT包含的用户信息进行其他逻辑操作,返回相应结果。
2.JWT优势
可以通过URL,POST参数或者在HTTP,header发送 ,因为数据量小,传输速度也很快。
自包含(self-contained): 负载中包含了所有用户所需要的信息,避免了多次查询数据库。
因为Token是以JSON加密的形式保存在客户端的,所以JWT是跨语言的,原则上任何web形式都支持。
不需要在服务端保存会话信息,特别适用于分布式微服务。

3.JWT结构
a.令牌组成
token 其实就相当于一段字符串 ==> token String ==>header.payload.singnature =token
1.标头(Header)
2.有效载荷(Payload)
3.签名(Signature)
因此,JWT通常如下所示:xxxx.yyyy.zzzz

4.JWT常见异常信息
SignatureVerificationException  签名不一致
TokenExpiredException  令牌过期异常
AlgorithmMismatchException  算法不匹配异常(也就是解密与加密的算法不一样)
InvalidClaimExeption 失效的Payload异常  (就是Payload加解密前后信息不一致)


总的来说就是登录的时候使用jwt生成一个token,用户带着这个token去其他页面进行验证,需要配合拦截器来实现。

作者有自己写的单点登录的demo源码如有需要可随时滴滴~

单点登录demo

使用原理(新手切记):

登录成功生成token后,需要将token返回前端也就是代码中的map.put("token",token),前端需要把这个token加入到请求头中去,然后后端进行接口验证,切记拦截器建议拦截所有路径,放行登录接口(如拦截无法进行登录验证)

使用postman测试时,先调用登录接口生成token,然后调用其他接口时在Header里面设置content-Type,application, token=生成的token值,就可以实现token验证了。

直接复制即可测试使用,

首先要准备好一个util包

JWTutils.java

public class JWTutils {
    private  static  final  String  SING="!@#$%^&";

    /*
    * 生成token
    * */
    public  static  String getToken (Map map){
        Calendar instance=Calendar.getInstance();
        instance.add(Calendar.MINUTE,15);//15分钟
        //创建JWT builder
        JWTCreator.Builder builder= JWT.create();
        map.forEach((k,v)->{
            builder.withClaim(k,v);
        });

        String token=builder.withExpiresAt(instance.getTime())//指定令牌过期时间
                .sign(Algorithm.HMAC256(SING)); //sign
        return  token;
    }
    /*
    * 验证token 合法性
    * */
//    //1.创建验证对象(采用加密时的算法)
//    JWTVerifier jwtVerifier=JWT.require(Algorithm.HMAC256("!@#$%^^&")).build();
//    //2.解密(报这个错说明是token时间过期了)(com.auth0.jwt.exceptions.
//    // TokenExpiredException: The Token has expired on Sat May 14 21:28:41 CST 2022.)
//    DecodedJWT verify=jwtVerifier.verify("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2NTI1MzU5ODEsInVzZXJJZCI6MjEsInVzZXJuYW1lIjoieGlhb2NoZW4ifQ.YGaiUwCOCmAyq0RUAA-61Et3TfTb61pZoTjgDbXiFJg");
    public  static DecodedJWT verify(String token){
     return  JWT.require(Algorithm.HMAC256(SING)).build().verify(token);

    }
    /*
    * 获取token信息方法   (该方法可以省略),可以直接在验证token方法中 renturn 返回
    * */
    public  static  DecodedJWT getTokenInfo(String token){
            DecodedJWT verify=JWT.require(Algorithm.HMAC256(SING)).build().verify(token);
            return  verify;
    }

}
JWTinterveptor.java(这里验证token)

public class JWTinterveptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Map map=new HashMap<>();
        //获取请求头中令牌
        String token =request.getHeader("token");

        try {
            JWTutils.verify(token); //去JWTutils中验证令牌
            return  true; //这一步到拦截器中去进行验证
        }catch (SignatureVerificationException e){
            e.printStackTrace();
            map.put("msg","无效签名");
        } catch (TokenExpiredException e){
            e.printStackTrace();
            map.put("msg","token过期");
        }catch (AlgorithmMismatchException e){
            map.put("msg","算法不一致");
        }catch (Exception e){
            map.put("msg","token无效");
        }
        map.put("state",false);//设置状态

        //将map转为json
        String json=new ObjectMapper().writeValueAsString(map);
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().println(json);
        return  false;
    }
}

InterceptorConfig.java(这里进行验证)

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new JWTinterveptor())
            .addPathPatterns("/**")//拦截  (其他接口token验证)
            .excludePathPatterns("/User/UserLogin");//所有用户都放行(登录接口不放行,无法进行登录)
    }
}

UserController.java(控制层)

package com.zufeng.lyh.controller;

import com.zufeng.lyh.domain.User;
import com.zufeng.lyh.service.UserService;
import com.zufeng.lyh.utils.JWTutils;
import jdk.nashorn.internal.parser.Token;
import org.springframework.beans.factory.annotation.Autowired;
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.RestController;

import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;

@GetMapping("/login")
    public Map login(User user){
            Map map=new HashMap<>();

                try {
                  User userDB= userService.login(user);


                  Map payload=new HashMap<>();
                  payload.put("id",userDB.getId());
                  payload.put("name",userDB.getName());
                    //生成JWT的令牌
                    String token=JWTutils.getToken(payload);
                    JWTutils.getToken(payload);

                    map.put("state",true);
                    map.put("msg","认证成功");
                    map.put("token",token);//传送token
                }catch (Exception e){
                e.printStackTrace();
                    map.put("state",false);
                }
            return  map;
    }

    @PostMapping("/test")
        public  Map test(HttpServletRequest request){
                    Map map=new HashMap<>();

                                

                //处理自己的业务逻辑
                    map.put("state",true);
                    map.put("msg","请求成功");
                    return map;
    }

}

over!!!

你可能感兴趣的:(java,开发语言,spring,intellij-idea,maven)