当前位置:网站首页>Feign shares login information for request

Feign shares login information for request

2022-06-11 18:21:00 _ Xiao_

brief introduction

In development and some integration testing , The request invocation needs to be based on login , In the request, you need to carry the information obtained after login token Etc , This article explores this scenario

Background information description

The local experiment has three components :

  • Login service : Provide user login and other services , After calling the login interface , Get sequenced token Information
  • Business services : Business interface services , All access interfaces need login verification
  • Test service : It can be regarded as an integration test project , First, access the login service to log in , obtain token Information , Then go to the business service

Login services and business services , It is not explained in this chapter , The login service and business service login authentication in this chapter are based on SaToken To build , You can refer to a previous blog article :Sa-Token Single sign on SSO Model 2 URL Redirect propagation session example

Without further ado , Here is the code description for testing the service

Maven Configuration information

Use in engineering spring Basis and feign, It's a separate project , The configuration is as follows :

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.0</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>com.self.growth</groupId>
    <artifactId>integration-test</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>integration-test</name>
    <description>integration-test</description>

    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
            <version>3.1.2</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

Engineering configuration information

We need to do some configuration , as follows :

test:
  #  User name and password for logging in to the service 
  login:
    username: username
    password: password
  server:
    #  The request address of the business service 
    record:
      url: http://localhost:9050
    #  Request address for login service 
    auth:
      url: http://localhost:9000

spring:
  main:
    allow-bean-definition-overriding: true

Feign Client and interceptor configuration

The client of the login service is defined as follows :

package com.self.growth.integration.test.feign;

import com.self.growth.integration.test.vo.ResResult;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

@FeignClient(
        value = "UserClient",
        url = "${test.server.auth.url}"
)
public interface UserClient {
    

    @RequestMapping(method = RequestMethod.GET, value = "/sso/doLogin")
    ResponseEntity<ResResult<Void>> login(@RequestParam("name") String name, @RequestParam("pwd") String pwd);
}

The above defines the client request url, And a login request , It uses ResponseEntity, Use this to get the returned header Information , And after logging in token It's going back to header Inside , This login service will be described in more detail later

Here you need a login Service, Process incoming requests , preservation token Information

package com.self.growth.integration.test.service;

import com.self.growth.integration.test.config.SaTokenContext;
import com.self.growth.integration.test.feign.UserClient;
import com.self.growth.integration.test.vo.ResResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import java.util.Objects;

@Slf4j
@Service
public class UserService {
    

    private final UserClient userClient;
    private final SaTokenContext saTokenContext;
    @Value("${test.login.username}")
    private String username;
    @Value("${test.login.password}")
    private String password;

    private boolean isLogin = false;

    public UserService(UserClient userClient, SaTokenContext saTokenContext) {
    
        this.userClient = userClient;
        this.saTokenContext = saTokenContext;
    }

    public void login() {
    
        if (!isLogin) {
    
            ResponseEntity<ResResult<Void>> res = userClient.login(username, password);
            if (Objects.requireNonNull(res.getBody()).getCode() != 200) {
    
                throw new RuntimeException(" User login failed ");
            }
            isLogin = true;
            log.info(" Login successful ");
            //  The token Preservation 
            saTokenContext.refreshToken(res.getHeaders());
        }
    }
}

The logic of login should be simple and clear ,saTokenContext It can be seen that it is a single case , To preserve and provide Token Information , The specific code is as follows :

package com.self.growth.integration.test.config;

import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
public class SaTokenContext {
    

    private String token;
    private String key;

    /** *  Get... From the login return results Token Information  * *  be based on SaToken Login authentication framework , Processing ahead of time for the specific return  * @param headers  Login back to headers */
    public void refreshToken(final HttpHeaders headers) {
    
        final List<String> setCookie = headers.get("set-cookie");
        assert setCookie != null;
        if (setCookie.isEmpty()) {
    
            return;
        }
        final String originCookie = setCookie.get(0);
        key = originCookie.split(";")[0].split("=")[0];
        token = originCookie.split(";")[0].split("=")[1];
    }

    public String getToken() {
    
        return token;
    }

    public String getKey() {
    
        return key;
    }
}

After logging in above , We are right. Token Saved ,token Is used in subsequent requests , Add to request header

We use the global interception method here : The token Put it in the request head . The interceptors are as follows :

package com.self.growth.integration.test.config;

import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableFeignClients(basePackages = "com.self.growth.integration.test.feign")
public class FeignClientsConfigurationCustom implements RequestInterceptor {
    

    private final SaTokenContext saTokenContext;

    public FeignClientsConfigurationCustom(SaTokenContext saTokenContext) {
    
        this.saTokenContext = saTokenContext;
    }

    @Override
    public void apply(RequestTemplate template) {
    
        final String token = saTokenContext.getToken();
        if (token == null) {
    
            return;
        }
        template.header(saTokenContext.getKey(), saTokenContext.getToken());
    }
}

Last , Of business services Feign Client as follows , It's a simple one hello request :

package com.self.growth.integration.test.feign;

import com.self.growth.integration.test.vo.ResResult;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@FeignClient(
        value = "RecordHelloFeign",
        url = "${test.server.record.url}"
)
public interface RecordHelloClient {
    

    @RequestMapping(method = RequestMethod.GET, value = "/hello")
    ResResult<String> hello();
}

Test verification

Writing test classes :

Here is the test record , Every request , Call the login service ( In the login service, there is a logic to not login after login , Just log in once )

package com.self.growth.integration.test;

import com.self.growth.integration.test.service.UserService;
import org.junit.jupiter.api.BeforeEach;
import org.springframework.beans.factory.annotation.Autowired;

public abstract class BaseServerTest {
    

    @Autowired
    private UserService userService;

    @BeforeEach
    public void login() {
    
        userService.login();
    }
}

Test access to business services :

package com.self.growth.integration.test.record;

import com.self.growth.integration.test.BaseServerTest;
import com.self.growth.integration.test.feign.RecordHelloClient;
import com.self.growth.integration.test.service.UserService;
import com.self.growth.integration.test.vo.ResResult;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@Slf4j
@SpringBootTest
public class RecordServerTest extends BaseServerTest {
    

    @Autowired
    private RecordHelloClient recordHelloClient;

    @Test
    public void helloTest() {
    
        ResResult<String> res = recordHelloClient.hello();
        log.info(res.toString());
        Assertions.assertEquals(200, res.getCode());
    }
}

give the result as follows :

2022-05-29 08:07:10.695  INFO 16348 --- [           main] c.s.g.i.test.service.UserService         :  Login successful 
2022-05-29 08:07:11.959  INFO 16348 --- [           main] c.s.g.i.test.record.RecordServerTest     : ResResult(data=hello: 1, code=200, msg=null)

summary

This article is about Feign Share login information for an attempt , The use is to define the interceptor to add token To the request header

原网站

版权声明
本文为[_ Xiao_]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/162/202206111754151183.html