Oauth2认证及Spring Security Oauth2授权码模式

Oauth2认证

Oauth2简介

简介

第三方认证技术方案最主要是解决认证协议的通用标准问题,因为要实现跨系统认证,各系统之间要遵循一定的接口协议。

OAUTH协议为用户资源的授权提供了一个安全的、开放而又简易的标准。同时,任何第三方都可以使用OAUTH认证服务,任何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。业界提供了OAUTH的多种实现如PHP、JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的时间,因而OAUTH是简易的。互联网很多服务如Open API,很多大公司如Google,Yahoo,Microsoft等都提供了OAUTH认证服务,这些都足以说明OAUTH标准逐渐成为开放资源授权的标准。

Oauth协议目前发展到2.0版本,1.0版本过于复杂,2.0版本已得到广泛应用。

参考:https://baike.baidu.com/item/oAuth/7153134?fr=aladdin

Oauth 协议:https://tools.ietf.org/html/rfc6749

下边分析一个Oauth2认证的例子,网站使用微信认证的过程:

在这里插入图片描述

  1. 用户进入网站的登录页面,点击微信的图标以微信账号登录系统,用户是自己在微信里信息的资源拥有者。
    在这里插入图片描述

  2. 点击“微信”出现一个二维码,此时用户扫描二维码,开始给网站授权。

  3. 资源拥有者同意给客户端授权
     资源拥有者扫描二维码表示资源拥有者同意给客户端授权,微信会对资源拥有者的身份进行验证,验证通过后,微信会询问用户是否给授权网站访问自己的微信数据,用户点击“确认登录”表示同意授权,微信认证服务器会颁发一个授权码,并重定向到网站。

  4. 客户端获取到授权码,请求认证服务器申请令牌
     此过程用户看不到,客户端应用程序请求认证服务器,请求携带授权码。

  5. 认证服务器向客户端响应令牌
     认证服务器验证了客户端请求的授权码,如果合法则给客户端颁发令牌,令牌是客户端访问资源的通行证。此交互过程用户看不到,当客户端拿到令牌后,用户在网站看到已经登录成功。

  6. 客户端请求资源服务器的资源
     客户端携带令牌访问资源服务器的资源。网站携带令牌请求访问微信服务器获取用户的基本信息。

  7. 资源服务器返回受保护资源
     资源服务器校验令牌的合法性,如果合法则向用户响应资源信息内容。
    注意:资源服务器和认证服务器可以是一个服务也可以分开的服务,如果是分开的服务资源服务器通常要请求认证服务器来校验令牌的合法性。

Oauth2.0认证流程如下:
引自Oauth2.0协议rfc6749 https://tools.ietf.org/html/rfc6749
在这里插入图片描述

角色

客户端

本身不存储资源,需要通过资源拥有者的授权去请求资源服务器的资源,比如:Android客户端、Web客户端(浏览器端)、微信客户端等。

资源拥有者

通常为用户,也可以是应用程序,即该资源的拥有者。

授权服务器(也称认证服务器)

用来对资源拥有的身份进行认证、对访问资源进行授权。客户端要想访问资源需要通过认证服务器由资源拥有者授权后方可访问。

资源服务器

存储资源的服务器,比如,网站用户管理服务器存储了网站用户信息,网站相册服务器存储了用户的相册信息,微信的资源服务存储了微信的用户信息等。客户端最终访问资源服务器获取资源信息。

常用术语

  • 客户凭证(client Credentials):客户端的clientId和密码用于认证客户
  • 令牌(tokens):授权服务器在接收到客户请求后,颁发的访问令牌
  • 作用域(scopes):客户请求访问令牌时,由资源拥有者额外指定的细分权限(permission)

令牌类型

  • 授权码:仅用于授权码授权类型,用于交换获取访问令牌和刷新令牌
  • 访问令牌:用于代表一个用户或服务直接去访问受保护的资源
  • 刷新令牌:用于去授权服务器获取一个刷新访问令牌
  • BearerToken:不管谁拿到Token都可以访问资源,类似现金
  • Proof of Possession(PoP) Token:可以校验client是否对Token有明确的拥有权

特点

优点:

 更安全,客户端不接触用户密码,服务器端更易集中保护广泛传播并被持续采用短寿命和封装的token资源服务器和授权服务器解耦集中式授权,简化客户端HTTP/JSON友好,易于请求和传递token考虑多种客户端架构场景客户可以具有不同的信任级别

缺点:

 协议框架太宽泛,造成各种实现的兼容性和互操作性差不是一个认证协议,本身并不能告诉你任何用户信息。

Spring Security Oauth2授权码模式

  1. 创建项目
  2. 导入依赖
 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-oauth2</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-security</artifactId></dependency><dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement>

3、编写实体类

package com.zuxia.entity;import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;import java.util.Collection;
import java.util.List;/*** 用户类*/
public class User implements UserDetails {private String username;private String password;private List<GrantedAuthority> authorities;@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {return authorities;}@Overridepublic String getPassword() {return password;}@Overridepublic String getUsername() {return username;}@Overridepublic boolean isAccountNonExpired() {return true;}@Overridepublic boolean isAccountNonLocked() {return true;}@Overridepublic boolean isCredentialsNonExpired() {return true;}@Overridepublic boolean isEnabled() {return true;}
}

4.编写配置类
SecurityConfig.java

package com.zuxai.springsecurityoauth2demo.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;/*** Spring Security 配置类**/
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}@Overridepublic void configure(HttpSecurity http) throws Exception {http.csrf().disable()//关闭csrf.authorizeRequests()//授权.antMatchers("/oauth/**", "/login/**", "/logout/**").permitAll()//放行授权服务器端点.anyRequest().authenticated()//拦截所有的请求.and()//通过and()可以配置多个http.formLogin().permitAll();//放行所有的表单请求}
}

5.编写自定义登录逻辑

UserService.java

package com.zuxia.springsecurityoauth2demo.service;import com.yjxxt.springsecurityoauth2demo.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;@Service
public class UserService implements UserDetailsService {@Autowiredprivate PasswordEncoder passwordEncoder;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {String password = passwordEncoder.encode("123456");return new User("admin",password, AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));}
}

6.授权服务器配置
AuthorizationServerConfig

package com.zuxia.springsecurityoauth2demo.config;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;/*** 授权服务器配置*/
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {@Autowiredprivate PasswordEncoder passwordEncoder;@Overridepublic void configure(ClientDetailsServiceConfigurer clients) throws Exception {		//获取授权码//http://localhost:8080/oauth/authorizeresponse_type=code&client_id=admin&redirect_uri=http://www.baidu.com&scope=all clients.inMemory()//配置client_id.withClient("admin")//配置client-secret.secret(passwordEncoder.encode("112233"))//配置redirect_uri,用于授权成功后跳转.redirectUris("http://www.baidu.com")//配置申请的权限范围.scopes("all")//配置grant_type,表示授权类型  authorization_code授权码模式.authorizedGrantTypes("authorization_code");}
}

7.资源服务器配置
ResourceServerConfig.java

package com.zuxia.springsecurityoauth2demo.config;import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;/*** 资源服务器配置  * 负责放行资源的路径*/
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {@Overridepublic void configure(HttpSecurity http) throws Exception {http.authorizeRequests()//授权.anyRequest().authenticated()//都进行认证.and().requestMatchers().antMatchers("/user/**");//配置需要保护的资源路径}
}

8.配置资源类

package com.zuxia.springsecurityoauth2demo.controller;import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/user")
public class UserController {@GetMapping("/getCurrentUser")public Object getCurrentUser(Authentication authentication) {return authentication.getPrincipal();//返回当前登录用户的具体对象}
}

9.测试
获取授权码
http://localhost:8080/oauth/authorize?response_type=code&client_id=admin&redirect_uri=http://www.baidu.com&scope=all

///oauth/authorize:授权服务器的授权端点
//response_type:返回类型
后面三个参数对应授权服务器配置中的配置
在这里插入图片描述

输入账户密码
在这里插入图片描述

点击授权获取授权码
在这里插入图片描述

根据授权码获取令牌(POST请求)
在这里插入图片描述
在这里插入图片描述

  • grant_type:授权类型,填写authorization_code,表示授权码模式
  • code:授权码,就是刚刚获取的授权码,注意:授权码只使用一次就无效了,需要重新申请。
  • client_id:客户端标识
  • redirect_uri:申请授权码时的跳转url,一定和申请授权码时用的redirect_uri一致。
  • scope:授权范围。

认证失败服务端返回 401 Unauthorized

注意:此时无法请求到令牌,访问服务器会报错
在这里插入图片描述

根据token去资源服务器拿资源
在这里插入图片描述

如果修改token就会报错
在这里插入图片描述

Spring Security Oauth2 密码模式

在上面的代码中进行适当的修改即可

SecurityConfig.java

package com.zuxia.springsecurityoauth2demo.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;/*** Spring Security 配置类**/
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}//使用密码模式需要配置@Bean@Overridepublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}@Overridepublic void configure(HttpSecurity http) throws Exception {http.csrf().disable().authorizeRequests().antMatchers("/oauth/**", "/login/**", "/logout/**").permitAll().anyRequest().authenticated().and().formLogin().permitAll();}
}

AuthorizationServerConfig.java

package com.zuxia.springsecurityoauth2demo.config;import com.yjxxt.springsecurityoauth2demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;/*** 授权服务器配置*/
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {@Autowiredprivate PasswordEncoder passwordEncoder;@Autowiredprivate AuthenticationManager authenticationManager;@Autowiredprivate UserService userService;/*** 使用密码模式需要配置*/@Overridepublic void configure(AuthorizationServerEndpointsConfigurer endpoints) {endpoints//授权管理器.authenticationManager(authenticationManager)//自定义登录逻辑.userDetailsService(userService);}@Overridepublic void configure(ClientDetailsServiceConfigurer clients) throws Exception {clients.inMemory()//配置client_id.withClient("admin")//配置client-secret.secret(passwordEncoder.encode("112233"))//配置访问token的有效期.accessTokenValiditySeconds(3600)//配置刷新token的有效期.refreshTokenValiditySeconds(864000)//配置redirect_uri,用于授权成功后跳转.redirectUris("http://www.baidu.com")//配置申请的权限范围.scopes("all")//配置grant_type,表示授权类型.authorizedGrantTypes("authorization_code","password");}
}

测试:
在这里插入图片描述
在这里插入图片描述

在Redis中存储token

之前的代码我们将token直接存在内存中,这在生产环境中是不合理的,下面我们将其改造成存储在Redis中

1.添加依赖及配置

<!--redis 依赖-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- commons-pool2 对象池依赖 -->
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId>
</dependency>

application.properties

# Redis配置
spring.redis.host=192.168.10.100

编写Redis配置类

RedisConfig.java

package com.zuxia.springsecurityoauth2demo.config;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;/*** 使用redis存储token的配置*/
@Configuration
public class RedisConfig {@Autowired//注入redis的连接工厂private RedisConnectionFactory redisConnectionFactory;@Beanpublic TokenStore redisTokenStore(){return new RedisTokenStore(redisConnectionFactory);}}

在认证服务器配置中指定令牌的存储策略为Redis

package com.zuxia.springsecurityoauth2demo.config;import com.yjxxt.springsecurityoauth2demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;/*** 授权服务器配置*/
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {@Autowiredprivate PasswordEncoder passwordEncoder;@Autowiredprivate AuthenticationManager authenticationManager;@Autowiredprivate UserService userService;@Autowired@Qualifier("redisTokenStore")private TokenStore tokenStore;/*** 使用密码模式需要配置*/@Overridepublic void configure(AuthorizationServerEndpointsConfigurer endpoints) {endpoints//权限管理器.authenticationManager(authenticationManager)//自定义登录逻辑.userDetailsService(userService)//令牌存储位置.tokenStore(tokenStore);}@Overridepublic void configure(ClientDetailsServiceConfigurer clients) throws Exception {clients.inMemory()//配置client_id.withClient("admin")//配置client-secret.secret(passwordEncoder.encode("112233"))//配置访问token的有效期.accessTokenValiditySeconds(3600)//配置刷新token的有效期.refreshTokenValiditySeconds(864000)//配置redirect_uri,用于授权成功后跳转.redirectUris("http://www.baidu.com")//配置申请的权限范围.scopes("all")//配置grant_type,表示授权类型.authorizedGrantTypes("password");}
}

测试:

使用密码模式请求token
在这里插入图片描述

JWT

常见的认证机制

HTTP Basic Auth

HTTP Basic Auth简单点说明就是每次请求API时都提供用户的username和password,简言之,Basic Auth是配合RESTful API 使用的最简单的认证方式,只需提供用户名密码即可,但由于有把用户名密码暴露给第三方客户端的风险,在生产环境下被使用的越来越少。因此,在开发对外开放的RESTful API时,尽量避免采用HTTP Basic Auth。

Cookie Auth

Cookie认证机制就是为一次请求认证在服务端创建一个Session对象,同时在客户端的浏览器端创建了一个Cookie对象;通过客户端带上来Cookie对象来与服务器端的session对象匹配来实现状态管理的。默认的,当我们关闭浏览器的时候,cookie会被删除。但可以通过修改cookie 的expire time使cookie在一定时间内有效。
 在这里插入图片描述

OAuth

OAuth(开放授权,Open Authorization)是一个开放的授权标准,允许用户让第三方应用访问该用户在某一web服务上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用。如网站通过微信、微博登录等,主要用于第三方登录。

OAuth允许用户提供一个令牌,而不是用户名和密码来访问他们存放在特定服务提供者的数据。每一个令牌授权一个特定的第三方系统(例如,视频编辑网站)在特定的时段(例如,接下来的2小时内)内访问特定的资源(例如仅仅是某一相册中的视频)。这样,OAuth让用户可以授权第三方网站访问他们存储在另外服务提供者的某些特定信息,而非所有内容。

下面是OAuth2.0的流程:
在这里插入图片描述
这种基于OAuth的认证机制适用于个人消费者类的互联网产品,如社交类APP等应用,但是不太适合拥有自有认证权限管理的企业应用。

缺点:过重。

Token Auth

使用基于 Token 的身份验证方法,在服务端不需要存储用户的登录记录。大概的流程是这样的:

  1. 客户端使用用户名跟密码请求登录
  2. 服务端收到请求,去验证用户名与密码
  3. 验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端
  4. 客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里
  5. 客户端每次向服务端请求资源的时候需要带着服务端签发的 Token
  6. 服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据
    在这里插入图片描述
    比第一种方式更安全,比第二种方式更节约服务器资源,比第三种方式更加轻量。

具体,Token Auth的优点(Token机制相对于Cookie机制又有什么好处呢?):

  1. 支持跨域访问: Cookie是不允许垮域访问的,这一点对Token机制是不存在的,前提是传输的用户认证信息通过HTTP头传输.
  2. 无状态(也称:服务端可扩展行):Token机制在服务端不需要存储session信息,因为Token 自身包含了所有登录用户的信息,只需要在客户端的cookie或本地介质存储状态信息.
  3. 更适用CDN: 可以通过内容分发网络请求你服务端的所有资料(如:javascript,HTML,图片等),而你的服务端只要提供API即可.
  4. 去耦: 不需要绑定到一个特定的身份验证方案。Token可以在任何地方生成,只要在你的API被调用的时候,你可以进行Token生成调用即可.
  5. 更适用于移动应用: 当你的客户端是一个原生平台(iOS, Android,Windows 10等)时,Cookie是不被支持的(你需要通过Cookie容器进行处理),这时采用Token认证机制就会简单得多。
  6. CSRF:因为不再依赖于Cookie,所以你就不需要考虑对CSRF(跨站请求伪造)的防范。
  7. 性能: 一次网络往返时间(通过数据库查询session信息)总比做一次HMACSHA256计算的Token验证和解析要费时得多.
  8. 不需要为登录页面做特殊处理: 如果你使用Protractor 做功能测试的时候,不再需要为登录页面做特殊处理.
  9. 基于标准化:你的API可以采用标准化的 JSON Web Token (JWT). 这个标准已经存在多个后端库(.NET, Ruby, Java,Python, PHP)和多家公司的支持(如:Firebase,Google, Microsoft).

JWT简介

什么是JWT

JSON Web Token(JWT)是一个开放的行业标准(RFC 7519),它定义了一种简介的、自包含的协议格式,用于在通信双方传递json对象,传递的信息经过数字签名可以被验证和信任。JWT可以使用HMAC算法或使用RSA的公钥/私钥对来签名,防止被篡改。

官网: https://jwt.io/

标准: https://tools.ietf.org/html/rfc7519

JWT令牌的优点:

  1. jwt基于json,非常方便解析。
  2. 可以在令牌中自定义丰富的内容,易扩展。
  3. 通过非对称加密算法及数字签名技术,JWT防止篡改,安全性高。
  4. 资源服务使用JWT可不依赖认证服务即可完成授权。

缺点:

  1. JWT令牌较长,占存储空间比较大。

JWT组成

一个JWT实际上就是一个字符串,它由三部分组成,头部、载荷与签名。

头部(Header)

头部用于描述关于该JWT的最基本的信息,例如其类型(即JWT)以及签名所用的算法(如HMAC SHA256或RSA)等。这也可以被表示成一个JSON对象。

{"alg": "HS256","typ": "JWT"
}
  • typ:是类型。
  • alg:签名的算法,这里使用的算法是HS256算法

我们对头部的json字符串进行BASE64编码(网上有很多在线编码的网站),编码后的字符串如下:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9  

Base64是一种基于64个可打印字符来表示二进制数据的表示方法。由于2的6次方等于64,所以每6个比特为一个单元,对应某个可打印字符。三个字节有24个比特,对应于4个Base64单元,即3个字节需要用4个可打印字符来表示。JDK 中提供了非常方便的 BASE64Encoder和 BASE64Decoder,用它们可以非常方便的完成基于 BASE64 的编码和解码。

负载(Payload)

第二部分是负载,就是存放有效信息的地方。这个名字像是特指飞机上承载的货品,这些有效信息包含三个部分:

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

    iss: jwt签发者
    sub: jwt所面向的用户
    aud: 接收jwt的一方
    exp: jwt的过期时间,这个过期时间必须要大于签发时间
    nbf: 定义在什么时间之前,该jwt都是不可用的.
    iat: jwt的签发时间
    jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。

  • 公共的声明

公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息.但不建议添加敏感信息,因为该部分在客户端可解密.

  • 私有的声明

私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息。

这个指的就是自定义的claim。比如下面那个举例中的name都属于自定的claim。这些claim跟JWT标准规定的claim区别在于:JWT规定的claim,JWT的接收方在拿到JWT之后,都知道怎么对这些标准的claim进行验证(还不知道是否能够验证);而private claims不会验证,除非明确告诉接收方要对这些claim进行验证以及规则才行。

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

其中sub是标准的声明,name是自定义的声明(公共的或私有的)

然后将其进行base64编码,得到Jwt的第二部分:

 eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkphbWVzIiwiYWRtaW4iOnRydWV9  

提示:声明中不要放一些敏感信息。

签证、签名(signature)

jwt的第三部分是一个签证信息,这个签证信息由三部分组成:

  1. header (base64后的)
  2. payload (base64后的)
  3. secret(盐,一定要保密)

这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分:

8HI-Lod0ncfVDnbKIPJJqLH998duF9DSDGkx3gRPNVI

将这三部分用.连接成一个完整的字符串,构成了最终的jwt:

eyJhbGciOiJIUzI1NiIsInR9cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.8HI-Lod0ncfVDnbKIPJJqLH998duF9DSDGkx3gRPNVI  

注意:secret是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,所以,它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/199680.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

本地/笔记本/纯 cpu 部署、使用类 gpt 大模型

文章目录 1. 安装 web UI1.1. 下载代码库1.2. 创建 conda 环境1.3. 安装 pytorch1.4. 安装 pip 库 2. 下载大模型3. 使用 web UI3.1. 运行 UI 界面3.2. 加载模型3.3. 进行对话 使用 web UI 大模型文件&#xff0c;即可在笔记本上部署、使用类 gpt 大模型。 1. 安装 web UI 1…

php一句话木马免杀

php一句话木马免杀 针对于php一句话木马做免杀&#xff1a; 利用php动态函数的特性&#xff0c;将危险函数拆分成字符&#xff0c;最终使用字符串拼接的方式&#xff0c;然后重新拼接&#xff0c;后加括号执行代码&#xff0c;并且可以使用花指令进行包装&#xff0c;如无限i…

C++ DAY06 c++多态

简介 一个事物的多种形态 , 简称多态 物的多态 同一个人在不同人面前展现是不同的 如 : 在我面前 在对象面前 在朋友面前 在父母面前 事的多态 吃饭 中国人 筷子 熟食 美国人 刀叉 7 分熟 日本人 筷子 生食 印度人 手 睡觉 中国人 床上 日本人 榻榻米 侧卧 平躺…

【U8+】用友U8账套引入/还原,提示:逻辑文件‘UFModel’不是数据库的一部分。

【问题描述】 用友U8+账套引入(恢复账套)的时候,提示: 逻辑文件‘UFModel’不是数据库‘UFDATA_001_2015’的一部分。 请使用RESTORE FILELISTONLY来列出逻辑文件名。-2147217900 【解决方法】 查看用友U8+账套库正确的逻辑名称为【UFMODEL】和【UFMODEL_log】。 【案例…

​分享mfc140u.dll丢失的解决方法,针对原因解决mfc140u.dll丢失的问题

作为电脑小白&#xff0c;如果电脑中出现了mfc140u.dll丢失的问题&#xff0c;肯定会比较的慌乱。但是出现mfc140u.dll丢失的问题&#xff0c;其实也有很简单的办法&#xff0c;所以大家不用慌张&#xff0c;接下来就教大家解决办法&#xff0c;能够有效的解决mfc140u.dll丢失的…

MFC 对话框

目录 一、对话款基本认识 二、对话框项目创建 三、控件操作 四、对话框创建和显示 模态对话框 非模态对话框 五、动态创建按钮 六、访问控件 控件添加控制变量 访问对话框 操作对话框 SendMessage() 七、对话框伸缩功能实现 八、对话框小项目-逃跑按钮 九、小项…

C#中的is和as的使用和区别

目录 概述一、is操作符1. is操作符的语法2. is操作符的用途3. is操作符的使用示例4. is操作符与typeof操作符的区别 二、as操作符1. as操作符的语法2. as操作符的用途3. as操作符的使用示例4. as操作符与is操作符的区别和联系5. as操作符与is操作符的区别总结 概述 在C#编程语…

探寻欧洲市场的机遇:深度剖析欧洲跨境电商

随着全球化的不断推进&#xff0c;欧洲作为一个经济发达、多元文化共存的大陆&#xff0c;成为跨境电商发展的重要目标。本文将深入剖析欧洲跨境电商的机遇&#xff0c;分析欧洲市场的特点、挑战与前景&#xff0c;为企业提供在这个充满潜力的市场中蓬勃发展的指导。 欧洲市场的…

【前端学java】java中的Object类(8)

往期回顾&#xff1a; 【前端学java】JAVA开发的依赖安装与环境配置 &#xff08;0&#xff09;【前端学 java】java的基础语法&#xff08;1&#xff09;【前端学java】JAVA中的packge与import&#xff08;2&#xff09;【前端学java】面向对象编程基础-类的使用 &#xff08…

YOLOv8-Seg改进:位置信息的轴线压缩增强注意力Sea_Attention| ICLR2023 SeaFormer,轻量级语义分割算法,复旦大学和腾讯

🚀🚀🚀本文改进:位置信息的轴线压缩增强注意力Sea_Attention,一方面将QKV特征进行轴线压缩后再注意力增强,另一方面将QKV特征使用卷积网络提升局部信息,最后将二者融合,输出增强特征 🚀🚀🚀Sea_Attention小目标分割首选,暴力涨点 🚀🚀🚀YOLOv8-seg创新…

LeetCode【76】最小覆盖子串

题目&#xff1a; 思路&#xff1a; https://segmentfault.com/a/1190000021815411 代码&#xff1a; public String minWindow(String s, String t) { Map<Character, Integer> map new HashMap<>();//遍历字符串 t&#xff0c;初始化每个字母的次数for (int…

redis 非关系型数据库

redis 非关系型数据库&#xff0c;缓存型数据库。 关系型数据库和非关系型数据库的区别 关系型数据库是一个机构化的数据库&#xff0c;行和列。 列&#xff1a;声明对象 行&#xff1a;记录对象属性。 表与表之间是有关联&#xff0c;使用sql语句&#xff0c;来对指定的表…

【Linux】指令详解(二)

目录 1. 前言2. 重新认识指令2.1 指令的本质2.1.1 which2.1.2 alias 3. 常见指令3.1 whoami3.2 cd3.2.1 cd -3.2.2 cd ~ 3.3 touch3.3.1 文件创建时间 3.4 stat3.5 mkdir3.5.1 创建一个目录3.5.2 创建路径 3.6 tree3.7 rm3.7.1 rm -f3.7.2 rm -r 3.8 man3.9 cp3.10 mv 1. 前言 …

键盘快捷键工具Keyboard Maestro mac中文版介绍

Keyboard Maestro mac是一款键盘快捷键工具&#xff0c;它可以帮助用户通过自定义快捷键来快速完成各种操作&#xff0c;提高工作效率。Keyboard Maestro支持多种快捷键组合&#xff0c;包括单键、双键、三键、四键组合等&#xff0c;用户可以根据自己的习惯进行设置。此外&…

扩散模型实战(十):Stable Diffusion文本条件生成图像大模型

推荐阅读列表&#xff1a; 扩散模型实战&#xff08;一&#xff09;&#xff1a;基本原理介绍 扩散模型实战&#xff08;二&#xff09;&#xff1a;扩散模型的发展 扩散模型实战&#xff08;三&#xff09;&#xff1a;扩散模型的应用 扩散模型实战&#xff08;四&#xff…

【智能家居】5、主流程设计以及外设框架编写与测试

目录 一、主流程设计 1、工厂模式结构体定义 &#xff08;1&#xff09;指令工厂 inputCmd.h &#xff08;2&#xff09;外设工厂 controlDevices.h 二、外设框架编写 1、创建外设工厂对象bathroomLight 2、编写相关函数框架 3、将浴室灯相关操作插入外设工厂链表等待被调…

揭开副业的神秘面纱,上班摸鱼搞副业

副业没那么神秘&#xff0c;说白了就是销售。 卖文字、卖知识、卖技能、卖产品 ... 找对了渠道&#xff0c;有人愿意买单&#xff0c;就成了副业。 但是现在搞副业&#xff0c;坑多水深的&#xff0c;太多人栽跟头了&#xff0c;丢几百块都能算少的。 开始细说干货之前&#…

DCDC同步降压控制器SCT82A30\SCT82630

SCT82A30是一款100V电压模式控制同步降压控制器&#xff0c;具有线路前馈。40ns受控高压侧MOSFET的最小导通时间支持高转换比&#xff0c;实现从48V输入到低压轨的直接降压转换&#xff0c;降低了系统复杂性和解决方案成本。如果需要&#xff0c;在低至6V的输入电压下降期间&am…

生产环境_移动目标轨迹压缩应用和算法处理-Douglas-Peucker轨迹压缩算法

场景&#xff1a; 我目前设计到的场景是&#xff1a;即在地图应用中&#xff0c;对GPS轨迹数据进行压缩&#xff0c;减少数据传输和存储开销&#xff0c;因为轨迹点太频繁了&#xff0c;占用空间太大&#xff0c;运行节点太慢了&#xff0c;经过小组讨论需要上这个算法&#x…

NGINX缓存详解之服务端缓存

服务端缓存 proxy cache属于服务端缓存,主要实现 nginx 服务器对客户端数据请求的快速响应。 nginx 服务器在接收到被代理服务器的响应数据之后,一方面将数据传递给客户端,另一方面根据proxy cache的配置将这些数据缓存到本地硬盘上。 当客户端再次访问相同的数据时,nginx…