Spirng Cloud Feign[‘装作’–“安装’工作区’作业”] WebService客户端,目的:是让WebService调用更加简单。
Feign-(调用服务Client客户端 ) > 此组件优势:
- Feign 是一个声明式的Web Service(Web服务)客户端、模版化的HTTP客户端。
- 可以做到使用HTTP 请求访问远程服务/Feign会完全代理HTTP请求。
- 接口上添加@FeignClient注解-即可被SpringIoc依赖注入Bean中。
- Feingn 具备‘插拔性’ 注解。
- Feign 支持插拔的HTTP编码器和解码器/提供了HTTP请求模版。
- 支持/并整合了Hystrix(熔断机制)和它的Fallback(返回上次)。
- 增强了对Spring MVC的注解支持。
- 支持/并内整合了Ribbon(客户端-负载均衡工具)。
一、Feign入门案例
1-创建Maven工程,配置Maven依赖所示:
<!-- Spring Cloud OpenFeign的Starter的依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2-创建主入口程序main()并添加类上注解:
@SpringBootApplication
@EnableFeignClients <!--该注解表示当程序启动时,会进行包扫描所有带@EnableFeign注解的类并处理-->
public class SpringCloudFeignApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudFeignApplication.class, args);
}
}
3-编写FeignClient Service接口:
@FeignClient(name = "github-client",
url = "https://api.github.com", configuration = HelloFeignServiceConfig.class)
<!--表示手动指定 url=“调用地址/远程服务地址”-->
public interface HelloFeignService {
@RequestMapping(value = "/search/repositories", method = RequestMethod.GET)
String searchRepo(@RequestParam("q") String queryStr);
}
<!--该方法最终请求地址是:远程服务地址/方法定义路径?方法定义参数=请求参数值-->
<!--该方法最终请求地址是:https://api.github.com/search/repositories?q=spring-cloud-dubbo-->
4-编写Controoller层,并依赖注入FeignClient(Feign客户端):定义的接口类:HelloFeignService.Java
@RestController(控制层)
public class HelloFeignController {
@Autowired
private HelloFeignService helloFeignService;
// 服务消费者对位提供的服务
@GetMapping(value = "/search/github")
public String searchGithubRepoByStr(@RequestParam("str") String queryStr) {
return helloFeignService.searchRepo(queryStr);
}
}
该类==class HelloFeignController==是,服务消费者类 ==searchGithubRepoByStr()== 消费者请求方法
该接口==interface HelloFeignService==是,服务提供者-定义指定地址中间组件/中间请求的‘钥匙’/Fegin组件
5-编写通过tomactWeb服务器请求-返回JSON结果集。
Feign工作原理:
步骤:
1-主程序入口添加 @EnableFeignClients 注解开启对 @FeignClient 扫描加载处理。
2-扫描所有 @FeignClient的注解的接口类,并注入SpringIOC容器中。
3-其接口类中的方法被调用是,是通过JDK的代理方式, 生成具体的RequestTemplate(请求范本)对象。1
4-然后有RequestTemplate生成Request,然后Request交给Client去处理。2
5-最后Client被封装到LoadBalanceClient类,该类结合Ribbon负载均衡发起服务之间的调用。
@FeignClient注解里做了/写了什么/?
@Target(ElementType.TYPE) --@目标(元素类型.TYPE) 标识着被注释的interface接口作用目标在接口上。
@Retention(RetentionPolicy.RUNTIME) --保留@(保留政策.RUNTIME[运行时]-可被反射读取)
@Documented --备有证明文件的(声明式)
public @interface FeignClient {
@AliasFor("name")
String value() default "";
@Deprecated
String serviceId() default "";
@AliasFor("value")
String name() default "";
String qualifier() default ""
String url() default "";
-1. 一般用于调试,可以手动指定 @FeignClient调用地址。
boolean decode404() default false;
-1.-DeCode404-:当发生404错误❌时,如果该字段为true,
-2.会调用-DeCode-进行解码,否则抛出 FeignException 异常。
Class<?>[] configuration() default {};
-1. Feign配置类
-2. 可以自定义 Feign的:
-2-1.Encoder.(编码器)
-2-2.Decoder.(解码器)
-2-3.LogLevel.(日志级别)
-2-4.Contract.(协议)
-2-5.以上属性值状态。
Class<?> fallback() default void.class;
-1. 定义容错的处理类:
-2. 当调用远程接口失败或者超时时,会调用对应的容错逻辑.
-3 fallback指定的类必须实现 @FeignClient 标识的接口。
Class<?> fallbackFactory() default void.class;
-1. 工厂类🏭:-回退动作工厂-
-2. 用户生成-fakkBack类-示例;
-3. 通过这个属性可以实现每个接口通用的容错逻辑,减少重复的代码。
String path() default "";
-1.-path-定义当前 FeignClient的统一前缀。
boolean primary() default true;
-- 剩下的字段标识的意思,等大伙儿开问嘞 --
}
Feign 组件开启 ‘霸气模式’ 哈~~~
二、Feign开始GZIP压缩
1-支持对Request请求和Response响应-TransferInfo传输信息进行GZIP压缩,提高通信效率。
-上代码
- 配置—Appliction.YML
feign:
compression:
request:
enabled: true
# 配置压缩支持的MIME TYPE
mime-types: text/xml,application/xml,application/json
min-request-size: 2048 # 配置压缩数据大小的下限
response:
enabled: true # 配置响应GZIP压缩
开启GZIP压缩之后,Feign之间的调用通过二进制协议进行Transfer传输,其返回值需要修改为ResposeEntity<byte[]>才可以正常显示。👇代码👇
@FeignClient(name = "github-client", url = "https://api.github.com",
configuration = HelloFeignServiceConfig.class)
public interface HelloFeignService {
@RequestMapping(value = "/search/repositories", method = RequestMethod.GET)
ResponseEntity<byte[]> searchRepo(@RequestParam("q") String queryStr);
}
- 然后,启动主应用程序,打开浏览器访问正确URL-结果集会响应JSON格式Info。
三、Feign支持属性文件配置
-看配置信息文件
-1-对单个指定特定名称对Feign进行设置:
feign:
client:
config:
feignName: #需要配置的FeignName
connectTimeout: 5000 #连接超时时间
readTimeout: 5000 #读超时时间设置
looggerLevel: full #配置Feign的日志级别
errorDecoder: com.example.SimpleErrorDecoder #Feign的错误❌解码器
retryer: com.example.SimpleRetryer #配置重试
requestInterceptors: -com.example.FooRequestInterceptor
-com.example.BarRequestInterceptor #配置拦截器
decode404: false
encoder: com.example.SimpleEncoder # Feign的编码器
decoder: com.example.SimpleDecoder # Feign的解码器
contract: com.example,SimpleContract #Feign的Contract配置
-2-此方式作用于所有Feign配置方式:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {
........
Class<?>[] defaultConfiguration() default {};
-1. 使用-@EnableFeignClients-注解类中的该属性,
-2. 可以将默认配置写成一个类--....
-3. 比如:-创建配置类 'DefaultFeignConfiguration.java',
-4. 然后,在主程序的启动入口使用 defaultConfiguration()来引用-自定义配置类;
.........
}
– 展示主程序类上 ‘Annotation注解’
@SpringBootApplication
@EnableFeignClients(defaultConfiguration=DefaultFeignConfiguration.class)
public class SpringCloudFeignApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudFeignApplication.class, args);
}
}
- 兜兜转转一圈二,大家该理解了吧!!!
-3-配置全局Feign属性值:
feign:
client:
config:
defailt:
connectTimeout: 5000
readTimeout: 5000
loggerLevel: basic
注意 ⚠️⚠️⚠️:如果通过Java代码配置过Feign设置属性类,然后又通过属性文件的方式配置Feign;
| | | | | | | | | | 后者一定会覆盖前者的设置的,但可以配置feign.client.defult-to-properties=false,
| | | | | | | | | | 来改变Feign设置的生效的优先级。
四、Feign Client开启日志
-Feign 为每一个FeignClient都提供来一个 ‘Feign.Logger’ 实例,可以在配置中开启日志。
-步骤1:
'-在application.yml-中设置日志输出级别'
logging:
level:
cn.springcloud.book.feign.service.HelloFeignService: debug
-步骤2:
-1- 通过创建带有-@Configuration-注解的配置类,
-2- 去配置Bean,代码👇下面👇
@Configuration
public class HelloFeignServiceConfig {
/**
*
* Logger.Level 的具体级别如下:
NONE:不记录任何信息
BASIC:仅记录请求方法、URL以及响应状态码和执行时间
HEADERS:除了记录 BASIC级别的信息外,还会记录请求和响应的头信息
FULL:记录所有请求与响应的明细,包括头信息、请求体、元数据
* @return
*/
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
}
五、Feign-超时设置
-Feign的设置分两层,即Ribbon(客户端负载均衡)和Hystrix(熔断器)的调用,Hystrix默认是关闭的。
-当Feign和Ribbon整合了Hystrix之后,可能会出现首次调用失败问题,
-造成问题出现的原因分析如下:
–1.Hystrix 默认的超时时间是1秒.超过时间未做出响应,将进入FallBack(后退动作)代码。
–2.由于Bean的装配以及懒加载机制等,Feign首次请求都会比较慢。
–3.解决方式:(1)将Hystrix的超时时间调整大,例如- 5 秒--4. hystrix.command.default.exexcution.isolation.thread.timeoutlnMilliseconds:5000
–5.(2)禁用超时时间--6.hystrix.command.default.execution.timeout.enabled:false
–7 (3)使用Feign的时候直接关闭Hystrix,该方式不推荐使用
–8.feign.hystrix.enabled.false1)Ribbon超时设置:
ribbon.ReadTimeout: 120000 # 设置请求处理的超时时间
ribbon.ConnectTimeout:30000 # 设置请求连接的超时时间
> 2)Hystrix超时设置:
feign.hystrix.enabled: truehystrix #熔断机制
hystrix:
shareSecurityContext: true
command:
default:
circuitBreaker:
sleepWindowInMillisecodes: 100000
forceClosed: true
execution:
isolation:
thread:
timeoutInMillisecods: 600000
六、Feign默认Client 2
Feigin 在默认情况下使用的JDK原生的Client 2,没有连接池的。
-1-使用HTTP Client2替换Feign默认Client2:
<!-- 使用Apache HttpClient替换Feign原生httpclient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-httpclient</artifactId>
<version>8.17.0</version>
</dependency>
feign:
httpclient:
enabled: true
- 然后,启动Java主程序访问即可。
-2-使用 OkHttp2替换Feign默认Client2:
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
</dependency>
feign:
httpclient:
enabled: false
okhttp:
enabled: true
-3-使用 OkHttp2第二种方式 FeignOkHttpConfig.Java 配置类 替换Feign默认Client2:
@Configuration
@ConditionalOnClass(Feign.class)
@AutoConfigureBefore(FeignAutoConfiguration.class)
public class FeignOkHttpConfig {
@Bean
public okhttp3.OkHttpClient okHttpClient(){
return new okhttp3.OkHttpClient.Builder()
//设置连接超时
.connectTimeout(60, TimeUnit.SECONDS)
//设置读超时
.readTimeout(60, TimeUnit.SECONDS)
//设置写超时
.writeTimeout(60,TimeUnit.SECONDS)
//是否自动重连
.retryOnConnectionFailure(true)
.connectionPool(new ConnectionPool())
//构建OkHttpClient对象
.build();
}
}
- 最后,启动Java主程序访问即可。
六、Feign的Post()和Get() 两种方式多参数传递-通过Feign拦截器方式处理
大家儿都知道,在Web开发中Spring MVC 是支持Get()方法直接绑定POJO(实体类)的,
最常见的解决方式如下:
1- 把POJO(实体类)拆散成一个一个单独的属性放在方法参数里。
2- 把方法参数变成Map传递。
3- 使用Get传递@RequesBody,但此方式违反Restful规范。
--------------------------------------------------------------------------- 666
下面我使用Feign拦截器的方式处理–:
表6-1 多参数传递工程集合
工程名 | 端口 | 描述 |
R6-1-Eureka-Server | 8761 | 注册中心 |
R6-1-Consumer | 8011 | GET或POST 请求多个参数传递的服务消费者,集成了Swagger用于测试 |
R6-1-Provider | 8012 | GET或POST 请求多参数传递的服务提供者 |
<!-- R6-1-Consumer 工程 Maven-->
<!-- Spring Cloud OpenFeign的Starter的依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- Swagger 的依赖 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.5.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.5.0</version>
</dependency>
<!-- R6-1-Consumer 工程 application.yml-->
server:
port: 8011
spring:
application:
name: r6-1-consumer
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka
<!-- R6-1-Consumer 工程 配置Swagger Config类集-->
(1)
@Configuration
@EnableWebMvc
public class ApplicationExceptionAdapter extends WebMvcConfigurerAdapter {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}
(2)
@Configuration
@EnableSwagger2
public class Swagger2Config {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select()
.apis(RequestHandlerSelectors
.basePackage("cn.springcloud.book.feign.controller"))
.paths(PathSelectors.any()).build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder().title("Feign多参数传递问题").description("Feign多参数传递问题")
.contact("Software_King@qq.com").version("1.0").build();
}
}
<!-- R6-1-Consumer 工程 自定义拦截器类-->
@Component
public class FeignRequestInterceptor implements RequestInterceptor {
@Autowired
private ObjectMapper objectMapper;
@Override
public void apply(RequestTemplate template) {
// feign 不支持 GET 方法传 POJO, json body转query
if (template.method().equals("GET") && template.body() != null) {
try {
JsonNode jsonNode = objectMapper.readTree(template.body());
template.body(null);
Map<String, Collection<String>> queries = new HashMap<>();
buildQuery(jsonNode, "", queries);
template.queries(queries);
} catch (IOException e) {
//提示:根据实践项目情况处理此处异常,这里不做扩展。
e.printStackTrace();
}
}
}
}
<!-- R6-1-Consumer 工程 Controller层-->
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserFeignService userFeignService;
/*** 用于演示Feign的Get请求多参数传递 * @param user * @return */
@RequestMapping(value = "/add", method = RequestMethod.POST)
public String addUser( @RequestBody
@ApiParam(name="用户",value="传入json格式",required=true) User user){
return userFeignService.addUser(user);
}
/** * 用于演示Feign的Post请求多参数传递 * @param user * @return*/
@RequestMapping(value = "/update", method = RequestMethod.POST)
public String updateUser( @RequestBody
@ApiParam(name="用户",value="传入json格式",required=true) User user){
return userFeignService.updateUser(user);
}
}
<!-- R6-1-Consumer 工程 Feign远程调用服务层-->
@FeignClient(name = "R6-1-Provider ")
public interface UserFeignService {
@RequestMapping(value = "/user/add", method = RequestMethod.GET)
public String addUser(User user);
@RequestMapping(value = "/user/update", method = RequestMethod.POST)
public String updateUser(@RequestBody User user);
}
<!-- R6-1-Consumer 工程 POJO实体类-->
public class User {
private Long id;
private String name;
private int age;
public Long getId() {return id;}
public void setId(Long id) {this.id = id;}
public String getName() {return name;}
public void setName(String name) {his.name = name;}
public int getAge() {return age;{}
public void setAge(int age) {this.age = age;}
}
<!-- R6-1-Provider 工程 application.yml-->
server:
port: 8012
spring:
application:
name: r6-1-provider
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
#eureka.instance.prefer-ip-address 表示将自己的IP注册到Eureka Server上,
#如果不配置,会将当前服务提供者所在的主机名注册到Eureka Server上。
instance:
prefer-ip-address: true
<!-- R6-1-Provider 工程 Controller层-->
@RestController
@RequestMapping("/user")
public class UserController {
@RequestMapping(value = "/add", method = RequestMethod.GET)
public String addUser(User user , HttpServletRequest request){
String token=request.getHeader("oauthToken");
return "hello,"+user.getName();
}
@RequestMapping(value = "/update", method = RequestMethod.POST)
public String updateUser( @RequestBody User user){
return "hello,"+user.getName();
}
}
<!-- R6-1-Eureka-Server 工程 Maven-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- springboot web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<artifactId>spring-boot-starter-tomcat</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
<!--不用Tomcat,使用undertow -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
<dependency>
<groupId>io.undertow</groupId>
<artifactId>undertow-servlet</artifactId>
</dependency>
<!-- R6-1-Eureka-Server 工程 bootstrap.yml -->
server:
port: 8761
eureka:
instance:
hostname: localhost
server :
enable-self-preservation: false
client:
registerWithEureka: false
fetchRegistry: false
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
- Swagger访问测试页面:http://localhost:8011/swagger-ui.html
- 大头儿复制粘贴完,分别启动各项目的Java主程序访问即可。
七、Feign的文件上传
表7-1 文件上传工程列表
工程名 | 端口 | 描述 |
R7-1-Eureka-Server | 8761 | 注册中心(之前上面👆自己找) |
R7-1-Feign-File-Server | 8012 | 模拟文件服务器,服务提供者 |
R7-1-Feign-Upload-Client | 8011 | 模拟文件表单上传,通过FeignClient发送文件到文件服务器(集成了Swagger 上面代码👆有) |
<!-- R7-1-Feign-Upload-Client 工程 Mavne -->
<!-- Feign文件上传依赖-->
<dependency>
<groupId>io.github.openfeign.form</groupId>
<artifactId>feign-form</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>io.github.openfeign.form</groupId>
<artifactId>feign-form-spring</artifactId>
<version>3.0.3</version>
</dependency>
<!-- R7-1-Feign-Upload-Client 工程 Service层-->
@FeignClient(value = "feign-file-server",
configuration = FeignMultipartSupportConfig.class)
public interface FileUploadFeignService {
/**** 1.produces,consumes必填
* 2.注意区分@RequestPart和RequestParam,不要将
* * @RequestPart(value = "file") 写成@RequestParam(value = "file")
* * @param file* @return*/
@RequestMapping(method = RequestMethod.POST, value = "/uploadFile/server",
produces = {MediaType.APPLICATION_JSON_UTF8_VALUE},
consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public String fileUpload(@RequestPart(value = "file") MultipartFile file);
}
<!-- R7-1-Feign-Upload-Client 工程 Controller层-->
@RestController
@Api(value="文件上传")
@RequestMapping("/feign")
public class FeignUploadController {
@Autowired
private FileUploadFeignService fileUploadFeignService;
@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@ApiOperation(value = "文件上传", notes = "请选择文件上传" )
public String imageUpload(@ApiParam(value="文件上传",required = true)
MultipartFile file ) throws Exception{
return fileUploadFeignService.fileUpload(file);
}
}
<!-- R7-1-Feign-Upload-Client 工程 Config层-->
/*** Feign文件上传Configuration*/
@Configuration
public class FeignMultipartSupportConfig {
@Bean
@Primary
@Scope("prototype")
public Encoder multipartFormEncoder() {
return new SpringFormEncoder();
}
}
- 大头儿二复制粘贴完,分别启动各项目的Java主程序访问即可。
八、Feign调用传递Token
-1 在进行认证鉴权的时候,不管是JWT认证 3 ,还是 Spring Security(安全性) 4 验证。
-2 当使用Feign时就会发现外部请求到A服务的时候,A服务是可以拿到Token的,
-3 然而当服务使用Feign调用是,Token就会小时,从而认证失败。
-4 解决方案:需要做当就是Feign调用时候,向Header(请求头)添加需要传递的Toten。
<!-- 首先需要实现Feign提供的一个接口RequestInterceptor,假设我们在验证权限的时候
放在请求头里面的key为oauthToken,先获取当前请求中的key为oauthToken的TOken,
然后放到Feign的请求Header上。-->
/*** Feign统一Token拦截器*/
@Component
public class FeignTokenInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate requestTemplate) {
if(null==getHttpServletRequest()){
//此处省略日志记录
return;
}
//将获取Token对应的值往下面传
requestTemplate.header("oauthToken",
getHeaders(getHttpServletRequest()).get("oauthToken"));
}
private HttpServletRequest getHttpServletRequest() {
try {
return ((ServletRequestAttributes)
RequestContextHolder.getRequestAttributes()).getRequest();
} catch (Exception e) {
return null;
}
}
/** * Feign拦截器拦截请求获取Token对应的值
* @param request * @return */
private Map<String, String> getHeaders(HttpServletRequest request) {
Map<String, String> map = new LinkedHashMap<>();
Enumeration<String> enumeration = request.getHeaderNames();
while (enumeration.hasMoreElements()) {
String key = enumeration.nextElement();
String value = request.getHeader(key);
map.put(key, value);
}
return map;
}
}
小结:哼~ 哼~ 哼 ! ! ! 总算将它‘码’完了。乐意为‘码’同志 解答噢 !!!
- RequestTemplate(请求范本)对象:“该对象封装了HTTP请求需要的全部信息,如:请求参数名、请求方法名、等信息。都是在这个过程中确定的。”
- ↩︎
- Client 在此指:可以是JDK原生的URLConnection、Apache的Http Client,也可以是Okhttp。
– 默认情况下使用的是JDK原生的URLConnection发送HTTP请求,没有连接池,但是对每个地址会保持一个长连接,即利用HTTP的 Persistence Connection(持续连接)。
– Apache Http Client 可设置连接池、超时时间等对服务之间的调用调优。
– OkHttp 是一个很棒的HTTP客户端,具有以下功能和特性:
– 支持SPDY,可以合并多个到同一个主机的请求。
– 使用连接池技术减少请求的延长。
– 使用GZIP压缩减少传输的数据量。
– 缓存响应避免重复的网络请求。 - ↩︎↩︎↩︎↩︎↩︎↩︎↩︎↩︎↩︎
- JSON Web Token(JWT)是一个非常轻巧的规范。这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息。
– JWT 工作流程:
– 1.用户导航到登录页,输入用户名、密码,进行登录
– 2.服务器验证登录鉴权,如果用户合法,根据用户的信息和服务器的规则生成JWT Token
– 3.服务器将该token以json形式返回(不一定要json形式,这里说的是一种常见的做法)
– 4.用户得到token,存在localStorage、cookie或其它数据存储形式中。
– 5.以后用户请求/protected中的API时,在请求的header中加入 Authorization: Bearer xxxx(token)。此处注意token之前有一个7字符长度的 Bearer
– 6.服务器端对此token进行检验,如果合法就解析其中内容,根据其拥有的权限和自己的业务逻辑给出对应的响应结果。
– 7.用户取得结果 - ↩︎
- Spring Security(安全性) 是为基于Spring的应用程序提供声明式安全保护的安全性框架。
– Web 应用的安全性包括用户认证(Authentication)和用户授权(Authorization) - ↩︎