一、跨域认证遇到的问题

由于多终端的出现,很多的站点通过 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. 【串线篇】SQL映射文件EmployeeDao.xml事项

    Dao.xml或者说是mapper.xml一个意思 id:方法名,相当于这个配置是对于某个方法的实现 ,参数类型不用写,()也不用写 resultType:指定方法运行后的返回值类型全类名:(查询操作 ...

  2. Electron-vue实战(一)—搭建项目与安装Element UI

    Electron-vue实战—搭建项目与安装Element UI 作者:狐狸家的鱼 本文链接 GitHub:sueRimn 一.新建项目1.初始化项目打开cmd,新建一个项目,我使用的是electro ...

  3. Qt + VS【无法打开xxx文件】

    在工程中右键点击属性-配置属性-VC++目录-包含目录-选择自己安装的qt路径下的头文件包含进去即可,烦人的下杠红线也随之消失.

  4. 数据结构---Java---HashMap---JDK1.7

    源码解读 public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Clone ...

  5. 【JZOJ1913】【BZOJ2124】等差子序列

    description 给一个1到N的排列{Ai},询问是否存在1<=p1<p2<p3<p4<p5<-<pLen<=N (Len>=3), 使得A ...

  6. cocos2D-X not config ndk path

    { 双击击那个error,那个路径就加上了 File = >local.properties }

  7. Homestead中PHP扩展无phpize难以安装redis扩展的问题及解决办法

    这真是一个非常深的坑.homestead中自带很多版本的php.然而扩展中缺没有phpize,这个东西是php添加扩展需要的东西本人在laravel中需要用到Redis扩展.这个和laravel的pr ...

  8. Android程序中欢迎界面

    额,在做项目中,肯定首先要用到欢迎界面,下面是我在做项目中用的最简单的一个欢迎界面,即打开程序时,先是显示一张图片,然后等一段时间后图片消失,进入登录界面.直接上代码,有注释也不用解释了: 首先是We ...

  9. CSS 设置鼠标显示形状

    CSS 设置鼠标显示形状 <style type="text/css"><!-- span {display:block;line-height:30px;mar ...

  10. 仅当使用了列列表并且 IDENTITY_INSERT 为 ON 时,才能为表'XXX'中的标识列指定显式值。

    (来自:https://zhidao.baidu.com/question/494717175.html)第一条回复,原因和例子都有了,解释的很好. 插入数据时,自增长列是系统自动处理,不需要你来指定 ...