一、跨域认证遇到的问题

由于多终端的出现,很多的站点通过 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. ORA-20782: Creating GGS_DDL_RULES

    在11g数据库上安装goldengate,运行@ddl_setup.sql时有如下错误 ERROR at line 1: ORA-20782: Creating GGS_DDL_RULES table ...

  2. HTML5 回到顶部

    图片: html <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> &l ...

  3. iview table的render()函数的用法

    语法:render:(h,params)=>{} render:(h,params) => { return h(" 定义的元素 ",{ 元素的性质 }," ...

  4. python核心编程socket备忘

    服务器端: # Echo server program from socket import * from time import ctime HOST = '' # Symbolic name me ...

  5. POJ1149PIGS

    传送门 貌似是最大流建图优化入门题(可惜我还是不会) 最暴力的建图当然是源点连每个猪圈然后猪圈需要拆成n个点分给每个人这个必定是跑不过的 所以我们可以进行优化 很明显没有被动过的猪圈一直是不变的可以不 ...

  6. Ceph的正确玩法之Ceph纠删码理论与实践

    http://blog.itpub.net/31545808/viewspace-2637083/ 注意空格,有的命令少空格 随着云计算业务的快速发展,国内外云计算企业的专利之争也愈发激烈.在云计算这 ...

  7. 切换路由时取消全部或者部分axios请求,并将一些从不需要取消的加入白名单

    1. axios拦截器进行配置,除了白名单中的接口,统统保存到全局变量canCancelAxios中 window.canCancelAxios = []; // http request 拦截器 a ...

  8. LINUXE下执行php 定时任务

    linux test.php <?php $fn='/home/root.adminssh/boz/logs'; $data=rand(1,9999); $fp=fopen($fn,'wb'); ...

  9. 在IIS7以上导出所有应用程序池的方法批量域名绑定(网站绑定)

    在IIS7+上导出所有应用程序池的方法: %windir%/system32/inetsrv/appcmd list apppool /config /xml > c:/apppools.xml ...

  10. CF_127E reader Display

    这道题其实找到规律之后其实不难,和破损的键盘一样,都有点递推转移的感觉 题意: 你可以进行这样一次操作:选一个点,然后把这个点横切竖切直到正对角线上面的点,全部翻转过来,问你要进行多少次操作才能把所有 ...