一、跨域认证遇到的问题

由于多终端的出现,很多的站点通过 web api restful 的形式对外提供服务,采用了前后端分离模式进行开发,因而在身份验证的方式上可能与传统的基于 cookieSession Id 的做法有所不同,除了面临跨域提交 cookie 的问题外,更重要的是,有些终端可能根本不支持 cookie

JWT(JSON Web Token) 是一种身份验证及授权方案,简单的说就是调用端调用 api 时,附带上一个由 api 端颁发的 token,以此来验证调用者的授权信息。

一般流程是下面这样:

1. 用户向服务器发送用户名和密码。
2. 服务器验证通过后,在当前对话(session)里面保存相关数据,比如用户角色、登录时间等等。
3. 服务器向用户返回一个 session_id,写入用户的 Cookie。
4. 用户随后的每一次请求,都会通过 Cookie,将 session_id 传回服务器。
5. 服务器收到 session_id,找到前期保存的数据,由此得知用户的身份。

这种模式的问题在于扩展性不好。单机没有问题,如果是服务器集群、跨域的服务导向架构或者用户禁用了 cookie ,就不行了。

二、解决方案

1. 单机和分布式应用下登录校验,session 共享

  • 单机和多节点 tomcat 应用登录检验

    ①、单机 tomcat 应用登录,sesssion 保存在浏览器和应用服务器会话之间,用户登录成功后,服务端会保证一个 session,也会给客户端一个 sessionId,客户端会把 sessionId 保存在 cookie 中,用户每次请求都会携带这个 sessionId

    ②、多节点 tomcat 应用登录,开启 session 数据共享后,每台服务器都能够读取 session。缺点是每个 session 都是占用内存和资源的,每个服务器节点都需要同步用户的数据,即一个数据需要存储多份到每个服务器,当用户量到达百万、千万级别的时,占用资源就严重,用户体验特别不好!!

  • 分布式应用中 session 共享

    ①、真实的应用不可能单节点部署,所以就有个多节点登录 session 共享的问题需要解决。tomcat 支持 session 共享,但是有广播风暴;用户量大的时候,占用资源就严重,不推荐

    ②、Reids 集群,存储登陆的 token,向外提供服务接口,Redis 可设置过期时间(服务端使用 UUID生成随机 64 位或者 128token ,放入 Redis 中,然后返回给客户端并存储)。

    ③、用户第一次登录成功时,需要先自行生成 token,然后将 token 返回到浏览器并存储在 cookie 中,

    并在 Redis 服务器上以 tokenkey,用户信息作为 value 保存。后续用户再操作,可以通过 HttpServletRequest 对象直接读取 cookie 中的 token,并在 Redis 中取得相对应的用户数据进行比较(用户每次访问都携带此 token,服务端去 Redis 中校验是否有此用户即可)。

    ④、 缺点:必须部署 Redis,每次必须访问 RedisIO 开销特别大。

2. 最终解决方案:使用 JWT 实现 Token 认证

  • JWT 的原理

    服务器认证以后,生成一个 JSON 对象发回给用户,以后用户与服务端通信的时候,都要发回这个 JSON 对象。服务器完全只靠这个对象认定用户身份。为了防止用户篡改数据,服务器在生成这个对象的时候,会加上签名。也就是说服务器就不保存任何 session 数据了,即服务器变成无状态了,从而比较容易实现扩展。

    简单来说,就是通过一定规范来生成 token,然后可以通过解密算法逆向解密 token,这样就可以获取用户信息
  • 优点和缺点

    优点:生产的 token 可以包含基本信息,比如 id、用户昵称、头像等信息,避免再次查库;存储在客户端,不占用服务端的内存资源

    缺点:token 是经过 base64 编码,所以可以解码,因此 token 加密前的对象不应该包含敏感信息(如用户权限,密码等)

  • JWT 格式组成:头部+负载+签名 ( header + payload + signature )

    头部:主要是描述签名算法。

    负载:主要描述是加密对象的信息,如用户的 id 等,也可以加些规范里面的东西,如 iss 签发者,exp 过期时间,sub 面向的用户。

    签名:主要是把前面两部分进行加密,防止别人拿到 token 进行base 解密后篡改 token。

3. 案例图设计

三、代码演示案例

  • pom.xml 文件引入依赖和实体类
    <!-- 依赖可以减少实体类 getter/setter等方法书写 -->
    <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
    </dependency>
    <!-- JWT相关 -->
    <dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.7.0</version>
    </dependency> ==================================================================================== @Getter
    @Setter
    @ToString
    @AllArgsConstructor
    @NoArgsConstructor
    public class User implements Serializable { private Integer id;
    private String openid;
    private String name;
    private String headImg;
    private String phone;
    private String sign;
    private Integer sex;
    private String city;
    private Date createTime; }
  • 生成 JWT 工具类
    public class JwtUtil {
    
        // 主题
    public static final String SUBJECT = "RookieLi"; // 秘钥
    public static final String SECRETKEY = "Rookie666"; // 过期时间
    public static final long EXPIRE = 1000 * 60 * 60 * 24 * 7; //过期时间,毫秒,一周 // 生成 JWT
    public static String geneJsonWebToken(User user) { if (user == null ||
    user.getId() == null ||
    user.getName() == null ||
    user.getHeadImg() == null) { return null;
    }
    String token = Jwts.builder()
    .setSubject(SUBJECT)
    .claim("id", user.getId())
    .claim("name", user.getName())
    .claim("img", user.getHeadImg())
    .setIssuedAt(new Date())
    .setExpiration(new Date(System.currentTimeMillis() + EXPIRE))
    .signWith(SignatureAlgorithm.HS256, SECRETKEY).compact(); return token;
    } // 校验 JWT
    public static Claims checkJWT(String token) { try {
    final Claims claims = Jwts.parser().setSigningKey(SECRETKEY).
    parseClaimsJws(token).getBody();
    return claims; } catch (Exception e) {
    e.printStackTrace();
    }
    return null;
    }
    }
  • 测试 JWT 工具类
    public class JwtUtilTest {
    
        @Test
    public void testGeneJwt(){ User user = new User();
    user.setId(999);
    user.setHeadImg("I'm busy");
    user.setName("Rookie");
    String token = JwtUtil.geneJsonWebToken(user);
    System.out.println(token); } @Test
    public void testCheck(){ // 下面此 token 字符串是上面的结果生成的,每次不一样,不是写死的
    String token = "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJSb29raWVMaSIsImlkIjo5OTksIm5hbWUiOiJSb29raWUiLCJpbWciOiJJJ20gYnVzeSIsImlhdCI6MTU2NzMxNjk4NywiZXhwIjoxNTY3OTIxNzg3fQ.FJh41VwVh2gh5-_cOG0SOgoO3dR_ZcK9VWNNskWqKl0";
    Claims claims = JwtUtil.checkJWT(token);
    if(claims != null){
    String name = (String)claims.get("name");
    String img = (String)claims.get("img");
    int id =(Integer) claims.get("id");
    System.out.println(name);
    System.out.println(img);
    System.out.println(id);
    }else{
    System.out.println("非法token");
    }
    }
    }

    参考博客:

    http://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html

    https://www.cnblogs.com/jpfss/p/10929458.html

SpringBoot 2.x 使用 JWT(JSON Web Token)的更多相关文章

  1. 如何在SpringBoot中集成JWT(JSON Web Token)鉴权

    这篇博客主要是简单介绍了一下什么是JWT,以及如何在Spring Boot项目中使用JWT(JSON Web Token). 1.关于JWT 1.1 什么是JWT 老生常谈的开头,我们要用这样一种工具 ...

  2. Java JWT: JSON Web Token

    Java JWT: JSON Web Token for Java and Android JJWT aims to be the easiest to use and understand libr ...

  3. JWT(JSON Web Token) 【转载】

    JWT(JSON Web Token) 什么叫JWTJSON Web Token(JWT)是目前最流行的跨域身份验证解决方案. 一般来说,互联网用户认证是这样子的. 1.用户向服务器发送用户名和密码. ...

  4. [更新]一份包含: 采用RSA JWT(Json Web Token, RSA加密)的OAUTH2.0,HTTP BASIC,本地数据库验证,Windows域验证,单点登录的Spring Security配置文件

    没有任何注释,表怪我(¬_¬) 更新: 2016.05.29: 将AuthorizationServer和ResourceServer分开配置 2016.05.29: Token获取采用Http Ba ...

  5. ( 转 ) 什么是 JWT -- JSON WEB TOKEN

    什么是JWT Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点 ...

  6. 关于JWT(Json Web Token)的思考及使用心得

    什么是JWT? JWT(Json Web Token)是一个开放的数据交换验证标准rfc7519(php 后端实现JWT认证方法一般用来做轻量级的API鉴权.由于许多API接口设计是遵循无状态的(比如 ...

  7. 什么是JWT(Json Web Token)

    什么是 JWT (Json Web Token) 用户认证是计算机安全领域一个永恒的热点话题. JWT 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519). 该to ...

  8. API安全验证之JWT(JSON WEB TOKEN) OLCMS

    假如www.olcms.com/getUserInfo获取用户信息,你怎么知道当前用户是谁?有人说登陆时候我把他UID写入session了,如果是API接口,没有session怎么办,那么就需要把UI ...

  9. 5分钟搞懂:JWT(Json Web Token)

    https://www.qikegu.com/easy-understanding/892 JWT 基于token的用户认证原理:让用户输入账号和密码,认证通过后获得一个token(令牌),在toke ...

  10. JWT(Json Web Token)认证

    目录 JWT(Json Web Token) JWT的数据结构 JWT的用法 JWT验证流程

随机推荐

  1. redis笔记3-命令

    通用命令:keys * --查询所有keykeys list* --查询list开头的keytype key1 --查询键对应的value类型del key --删除指定的keyttl key --查 ...

  2. 【Java 其他】Java opencv配置及测试

    毕竟研究生做cv,所以这里还是测试一下java上使用opencv,参考 这里 import org.opencv.core.Core; import org.opencv.core.CvType; i ...

  3. solaris系统动态查看swap的使用情况

    root@tt # root@tt # prstat  -aPlease wait... PID USERNAME  SIZE   RSS STATE  PRI NICE      TIME  CPU ...

  4. Future模式的简单实现

    /** * 数据接口 */ public interface Data { public String getResult(); } /** * 最终需要使用的数据模型 */ public class ...

  5. Sqli labs系列-less-5&6 报错注入法(上)

    在我一系列常规的测试后发现,第五关和第六关,是属于报错注入的关卡,两关的区别是一个是单引号一个是双引号...当然我是看了源码的.... 基于报错注入的方法,我早就忘的差不多了,,,我记的我最后一次基于 ...

  6. python基础三(深浅拷贝)

    1.赋值操作 list_1 = [1,2,3,['barry','Jerry']] list_2 = list_1 list_1[0] = 111 print(list_1) # [111, 2, 3 ...

  7. selenium自动化之验证,判断总结(持续更新)

    API命令 1,is_displayed() 例子:driver.find_element_by_css_selector("#id").is_displayed() 该元素是否可 ...

  8. 转:Linux设备树(Device Tree)机制

    目录 1. 设备树(Device  Tree)基本概念及作用 2. 设备树的组成和使用 2.1. DTS和DTSI 2.2. DTC 2.3. DTB 2.4. Bootloader 3. 设备树中d ...

  9. jsp中jstl、el使用

    tomcat7.0+JSTL1.1.2(不冲突) EL表达式获取变量 ${表达式} 如:${user.name} 不可以动态取值 ${user[name]}可以动态取值,变量名中含有特殊字符时只能用此 ...

  10. Linux命令 touch

    1.简介 改变文件或者目录的时间,可以更新文件的存取时间(atime,文件内容被读取的时候就会更改的时间)和更改时间(mtime,文件内容被更改是会变更的时间) 2.语法和参数 touch [参数] ...