Spring Cloud【实现用户鉴权(什么是JWT、JWT原理、用户微服务、JWT工具类、用户服务实现JWT鉴权)】(八)

 

目录

Gateway解决如何允许跨域

服务网关Gateway实现用户鉴权_什么是JWT

服务网关Gateway实现用户鉴权_JWT原理

服务网关Gateway实现用户鉴权_用户微服务

服务网关Gateway实现用户鉴权_JWT工具类

服务网关Gateway实现用户鉴权_用户服务实现JWT鉴权


 

Gateway解决如何允许跨域

Spring Cloud【实现用户鉴权(什么是JWT、JWT原理、用户微服务、JWT工具类、用户服务实现JWT鉴权)】(八)_第1张图片

CORS

1、如何允许跨域,一种解决方法就是目的域告诉请求者允许什么来源域来请求,那么浏览器就会知道 B域是否允许A域发起请求。

2、CORS("跨域资源共享"(Cross-origin resource sharing))就是这样一种解决手段。 

CORS使得浏览器在向目的域发起请求之前先发起一个OPTIONS方式的请求到目的域获取目的域的信息,比如获取目的域允许什么域来请求的信息。 

spring:
 cloud:
   gateway:
     globalcors:
       cors-configurations:
         '[/**]':
           allowCredentials: true
           allowedOriginPatterns: "*"
           allowedMethods: "*"
           allowedHeaders: "*"
       add-to-simple-url-handler-mapping: true

实时效果反馈

1.当一个请求url的____之间任意一个与当前页面url不同即为跨域。

A 协议、域名

B 协议、端口

C 协议、域名、请求类型

D 协议、域名、端口

2.最常用解决跨域的手段是____。

A CORS

B COS

C COR

D 以上都是错误

服务网关Gateway实现用户鉴权_什么是JWT

Spring Cloud【实现用户鉴权(什么是JWT、JWT原理、用户微服务、JWT工具类、用户服务实现JWT鉴权)】(八)_第2张图片

什么是JWT 

JWT是一种用于双方之间传递安全信息的简洁的、URL安全的声明规范。定义了一种简洁的,自包含的方法用于通信双方之间以Json对象的形式安全的传递信息。特别适用于分布式站点的单点登录 (SSO)场景。

传统的session认证 

每次提到无状态的 JWT时相信都会看到另一种基于Session 的用户认证方案介绍,这里也不例外,Session 的认证流程通常会像这样:

Spring Cloud【实现用户鉴权(什么是JWT、JWT原理、用户微服务、JWT工具类、用户服务实现JWT鉴权)】(八)_第3张图片 

缺点:

安全性:CSRF攻击因为基于cookie来进行用户识别, cookie如果被截获,用户就会很容易受 到跨站请求伪造的攻击。

扩展性:对于分布式应用,需要实现 session 数据共享

性能:每一个用户经过后端应用认证之后,后端应用都要在服务端做一次记录,以方便用户 下次请求的鉴别,通常而言session都是保存在内存中,而随着认证用户的增多,服务端的开 销会明显增大,与REST风格不匹配。因为它在一个无状态协议里注入了状态。 

JWT方式 

Spring Cloud【实现用户鉴权(什么是JWT、JWT原理、用户微服务、JWT工具类、用户服务实现JWT鉴权)】(八)_第4张图片

优点:

1、无状态

2、适合移动端应用

3、单点登录友好 

实时效果反馈

1.传统的session认证缺点的是__。

A 内存容量

B 网络安全

C 分布式应用session共享

D 以上都正确

2.下列属于JWT优点的是__。

A 无状态

B 适合移动端应用 

C 单点登录友好

D 以上都正确

服务网关Gateway实现用户鉴权_JWT原理

Spring Cloud【实现用户鉴权(什么是JWT、JWT原理、用户微服务、JWT工具类、用户服务实现JWT鉴权)】(八)_第5张图片

 JWT 的原理是,服务器认证以后,生成一个 JSON 对象,发回给用户,就像下面这样。

{
  "姓名": "张三",
  "角色": "管理员",
  "到期时间": "2030年7月1日0点0分"
}

 注意:

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

JWT的结构 

Spring Cloud【实现用户鉴权(什么是JWT、JWT原理、用户微服务、JWT工具类、用户服务实现JWT鉴权)】(八)_第6张图片

注意: 它是一个很长的字符串,中间用点( . )分隔成三个部分。注 意,JWT 内部是没有换行的,这里只是为了便于展示,将它写成了几行。 

JWT 的三个部分依次如下: 

头部(header)

载荷(payload)

签证(signature) 

Header 

JSON对象,描述 JWT 的元数据。其中 alg 属性表示签名的算法 (algorithm),默认是 HMAC SHA256(写成 HS256);typ 属性 表示这个令牌(token)的类型(type),统一写为 JWT。

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

 注意: 上面代码中, alg 属性表示签名的算法(algorithm),默认是 HMAC SHA256(写成 HS256); typ 属性表示这个令牌 (token)的类型(type),JWT 令牌统一写为 JWT 然后将头部进行Base64编码构成了第一部分,Base64是一种用64个字符来表示任意二进制数据的方法,Base64是一种任意二进制到文本字符串的编码方法,常用于在URL、Cookie、网页中传输少量二进制数据。

Payload 

Spring Cloud【实现用户鉴权(什么是JWT、JWT原理、用户微服务、JWT工具类、用户服务实现JWT鉴权)】(八)_第7张图片

内容又可以分为3中标准

1、标准中注册的声明

2、公共的声明

3、私有的声明 

payload-标准中注册的声明 (建议但不强制使用) :

iss: jwt签发者

sub: jwt所面向的用户 

aud: 接收jwt的一方

exp: jwt的过期时间,这个过期时间必须要大于签发时间

nbf: 定义在什么时间之前,该jwt都是不可用的.

iat: jwt的签发时间

jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。

payload-公共的声明 :

公共的声明可以添加任何的信息。一般这里我们会存放一下用户的基本信息(非敏感信息)。

payload-私有的声明 : 

私有声明是提供者和消费者所共同定义的声明。需要注意的是,不要存放敏感信息,不要存放敏感信息,不要存放敏感信息!!!

Spring Cloud【实现用户鉴权(什么是JWT、JWT原理、用户微服务、JWT工具类、用户服务实现JWT鉴权)】(八)_第8张图片

因为:这里也是base64编码,任何人获取到jwt之后都可以解码!! 

{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}

注意: sub和iat是标准声明,分别代表所面向的用户和jwt签发时间。

1、sub:这个是发给一个账号是1234567890的用户(也许是ID)

2、name:名字叫John Doe

3、iat:签发时间是1516239022(2030/1/18 9:30:22)

Signature 

这部分就是 JWT 防篡改的精髓,其值是对前两部分 base64UrlEncode 后使用指定算法签名生成,以默认 HS256 为例,指定一个密钥(secret),就会按照如下公式生成:

 

HMACSHA256(
 base64UrlEncode(header) + "." + base64UrlEncode(payload),
 secret,
)

注意: 算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"( . )分隔,就可以返回给用户。

JWT 的使用方式 

Spring Cloud【实现用户鉴权(什么是JWT、JWT原理、用户微服务、JWT工具类、用户服务实现JWT鉴权)】(八)_第9张图片

流程: 客户端收到服务器返回的 JWT,可以储存在 Cookie 里面,也可以储存在 localStorage。此后,客户端每次与服务器通信,都要带上这个 JWT。你可以把它放在 Cookie 里面自动发送,但是这样不能跨域,所以更好的做法是放在 HTTP 请求的头信息 Authorization 字段里面。 

实时效果反馈

1.客户端收到服务器返回的 JWT把数据保存到____。

A load

B session

C loadStorage

D 以上都是错误

2. JWT签证默认算法__。

A HS256 

B Base64

C HS384

D SR384

服务网关Gateway实现用户鉴权_用户微服务

Spring Cloud【实现用户鉴权(什么是JWT、JWT原理、用户微服务、JWT工具类、用户服务实现JWT鉴权)】(八)_第10张图片

创建cloud-auth-user6500工程 

Spring Cloud【实现用户鉴权(什么是JWT、JWT原理、用户微服务、JWT工具类、用户服务实现JWT鉴权)】(八)_第11张图片

引入POM依赖 


        
            org.springframework.boot
            spring-boot-starter-web
        
        
        
            org.springframework.boot
            spring-boot-starter-data-redis
        
       
        
            org.springframework.cloud
            spring-cloud-starter-netflix-eureka-client
        
        
            org.projectlombok
            lombok
            1.18.22
        
        
            org.springframework.boot
            spring-boot-starter-actuator
        
    

服务网关Gateway实现用户鉴权_JWT工具类

引入JWT依赖


     com.alibaba
     fastjson
     1.2.79


      com.auth0
      java-jwt
      3.7.0

创建JWT工具类JWTUtils

public class JWTUtil {
    // 秘钥
    public static final String SECRET_KEY = "erbadagang-123456";
    // token过期时间
    public static final long TOKEN_EXPIRE_TIME = 5 * 60 * 1000;
    // 签发人
    private static final String ISSUER = "issuer";
    // 用户名
    private static final String USER_NAME = "username";
    
}

生成签名方法

  public static String token(String username) {
        Date now = new Date();
        //SECRET_KEY是用来加密数据签名秘钥
        Algorithm algorithm = Algorithm.HMAC256(SECRET_KEY);
        String token = JWT.create()
                // 签发人
               .withIssuer(ISSUER)
                // 签发时间
               .withIssuedAt(now)
                // 过期时间
               .withExpiresAt(new Date(now.getTime() + TOKEN_EXPIRE_TIME))
                // 保存权限标记
               .withClaim(USER_NAME,username)
               .sign(algorithm);
        log.info("jwt generated user={}",username);
        return token;
   }

验证签名

public static boolean verify(String token)
{
        try {
            //SECRET_KEY是用来加密数据签名秘钥
            Algorithm algorithm = Algorithm.HMAC256(SECRET_KEY);
            JWTVerifier verifier = JWT.require(algorithm)
                   .withIssuer(ISSUER)
                   .build();
            //如果校验有问题会抛出异常。
            verifier.verify(token);
            return true;
       } catch (Exception ex) {
            ex.printStackTrace();
       }
        return false;
   }

测试JWT

public static void main(String[] args) {
       // 生成Token
        String token = JWTUtil.token("itbaizhan");
        System.out.println(token);
        
        //验证Token
        boolean verify = JWTUtil.verify("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJpc3N1ZXIiLCJleHAiOjE2NDUwNjMyNzYsImlhdCI6MTY0NTA2Mjk3NiwidXNlcm5hbWUiOiJpdGJhaXpoYW4ifQ.uKKVEMCTW0-e_bPHLyb-JY8CwRU7ciU8vP5B78lDY3s");
        System.out.println(verify);
   }

服务网关Gateway实现用户鉴权_用户服务实现JWT鉴权

编写LoginController类

@RequestMapping("user")
@RestController
@Slf4j
public class LoginController { }

编写统一返回实体类

/**
* AuthResult 作用 : 统一返回实体类
*/
@Data
@NoArgsConstructor
@Builder
public class AuthResult {
    // 返回状态码
    private int code;
    // 返回描述信息
    private String msg;
    // 返回Token签名
    private String token;
    public AuthResult(int i, String s) {
        this.code = i;
        this.msg = s;
   }
    public AuthResult(int i, String success, String token) {
        this.code = i;
        this.msg = success;
        this.token = token;
   }
}

编写用户登录接口

/**
     * 用户登录
     * @param username 用户名
     * @param password 密码
     * @return
     */
    @PostMapping("/login")
    public AuthResult login(String username,String password) {
        // TODO 模拟数据库验证用户名密码
        if ("admin".equals(username) && "admin".equals(password)) {
            //生成token
            String token = JWTUtil.token();
            return new AuthResult(0, "success", token, refreshToken);
       } else {
            return new AuthResult(1001,"username or password error");
       }
   }

编写验证令牌接口

/**
     * 验证令牌
     * @param token 令牌
     * @return
     */
    @GetMapping("/verify")
    public AuthResult verify(String token) {
        // 验证令牌
        boolean success = JWTUtil.verify(token);
        if (success){
            return AuthResult.builder()
                   .code(200).msg("Token未失效").build();
       }else {
            return AuthResult.builder()
                   .code(500).msg("Token失效").build();
       }
   }

YML文件编写

eureka:
 client:
    # 表示是否将自己注册到Eureka Server
   register-with-eureka: true
    # 示是否从Eureka Server获取注册的服务信息
   fetch-registry: true
    # Eureka Server地址
   service-url:
     defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
 instance:
   instance-id: user-service
   prefer-ip-address: true
spring:
 application:
    # 设置应用名词
   name: user-service
server:
 port: 6510

Postman测试

测试登录

Spring Cloud【实现用户鉴权(什么是JWT、JWT原理、用户微服务、JWT工具类、用户服务实现JWT鉴权)】(八)_第12张图片

 

你可能感兴趣的:(Spring全家桶,前端,Spring,Cloud,java,JWT)