Cabbage Java self study room covers core knowledge

Spring Cloud Alibaba combat (1) Prepare for Spring Cloud Alibaba combat (2) Nacos Article Spring Cloud Alibaba combat (3) Sentinel article Spring Cloud Alibaba Spring Cloud Alibaba (Zuul) Spring Cloud Alibaba (Zuul Cloud Alibaba Combat (8) SkyWalking

GitHub address: github.com/D2C-Cai/her…

1. Zuul profile

Zuul microservices Gateway is a framework for Spring Cloud Netflix to provide dynamic routing, monitoring, elasticity, security and other services. Works with Eureka, Ribbon, Hystrix, etc.

1.1. Main Functions of Zuul:

  • Authentication and security: Identify each resource that requires authentication and reject requests that do not meet the requirements.
  • Performance monitoring: Track and tally data at service boundaries to provide an accurate view of production.
  • Dynamic routing: Requests are dynamically routed to the back-end cluster as needed.
  • Stress test: Gradually increase traffic to the cluster to understand its performance.
  • Load offload: Capacity is allocated in advance for each type of request and is automatically discarded when the request exceeds capacity.
  • Static resource processing: Returns some responses directly at the boundary.

2. Introduction of Zuul gateway

Problems left over from OAUTH2 above:

The authentication logic is coupled with microservices. Each microservice needs to be set up separately, and the authentication logic is repeated many times. When a request microservice invocation link is very long, isn’t it necessary for each microservice to request Oauth2 authentication service (server) once, so as to form the relationship between the number of requests and authentication 1 than N, if the request traffic is relatively large, let oAuth2-Service bear great pressure.

2.1. What advantages does Zuul bring

Gateway service not used:

  1. The client requests different microservices multiple times, increasing the complexity of the client.
  2. Cross-domain requests exist and are complicated to process in certain scenarios.
  3. Authentication is complex and each service requires independent authentication.

After using the service gateway:

  1. Easy to monitor, monitoring data can be collected in the microservices gateway and pushed to external systems for analysis.
  2. Easy to authenticate, authentication can be done on the microservices portal and requests can be forwarded to the microservices on the back end instead of being authenticated in each microservice.
  3. Reduce the number of interactions between the client and each micro-service.

3. Rapid construction of Zuul gateway

  1. Add POM file dependencies:
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>
Copy the code
  1. Add @enableZuulProxy annotation:
@EnableZuulProxy @SpringBootApplication public class GatewayServiceApplication { public static void main(String[] args) { SpringApplication.run(GatewayServiceApplication.class, args); }}Copy the code

At this point, in theory, the Zuul gateway can be used directly.

3.1. Zuul integrates Oauth2 certification

We need to make some changes to the architecture of the Oauth2 service above:

  1. The Oauth2 authentication center (server) remains unchanged.
  2. Oauth2 resource Service (client) changed to Zuul network authentication.
  • Member service: herring-member-service, one of the micro services, will receive the request to the certification center verification.
  • Order service: herring orders-service, the second micro service, receives the request and goes to the certification center for verification.
  • Goods and services: herring product-service, the third micro service, will be verified by the certification center after receiving the request.
  1. Delete all codes related to Oauth2 in member services, order services and commodity services:

There are also some feign codes here, which can be retained or deleted. It is recommended to retain them, because although the gateway Zuul has unified authentication, a single micro-service still needs to use user information (such as user ID) for business purposes. The general practice is that after gateway Zuul decodes the authenticated token, The user information is brought into the request context and passed uniformly through Feign’s interceptor.

  1. In zuul service, add POM file dependencies:
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth2</artifactId>
        </dependency>
Copy the code

If additional information is added to the JWT, the user client will parse the JWT after receiving the token in JWT format.

<dependency> <groupId> IO. Jsonwebtoken </groupId> <artifactId> JJWT </artifactId> <version>0.9.1</version> </dependency>Copy the code
  1. Configuration of the ResourceServerConfig class:
@Configuration @EnableResourceServer @EnableGlobalMethodSecurity(prePostEnabled = true) public class JwtResourceServerConfig extends ResourceServerConfigurerAdapter { @Resource private TokenStore jwtTokenStore; @Bean public TokenStore jwtTokenStore() { return new JwtTokenStore(jwtAccessTokenConverter()); } @Bean public JwtAccessTokenConverter jwtAccessTokenConverter() { JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter(); accessTokenConverter.setSigningKey("sign-8888"); accessTokenConverter.setVerifierKey("sign-8888"); return accessTokenConverter; } @Override public void configure(ResourceServerSecurityConfigurer resources) throws Exception { resources.tokenStore(jwtTokenStore); resources.resourceId("gateway-service"); } @Override public void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/oauth/**").permitAll(); }}Copy the code

Note: There are two differences between the file here and the original microservices project.

  • ResourceId: change the database table to gateway-service.
        resources.resourceId("gateway-service");
Copy the code

What does that mean? Cleint-id =app-client, resource_ids=member-service,orders-service,product-service, cleint-id=app-client, resource_ids=member-service,orders-service,product-service App-client requests allow access to these resource servers; I am now resource_ids=gateway-service, which means that the request from the app-client is allowed to access the Zuul server, and I do not control the rest, leaving it all to the gateway.

  • Add request whitelist /oauth/**;
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/oauth/**").permitAll();
    }
Copy the code

Why is that? We assume that all requests go through the gateway Zuul and then to our microservice. Oauth2-service is a microservice, although it remains the same, because Zuul has added authentication logic. However, forwarding /oauth/** requests, such as login and token refresh, do not contain tokens and need to be whitelisted before entering the authentication center.

  1. Application. Yml configuration file:
server:
  port: 8080

spring:
  application:
    name: gateway-service
    
zuul:
  sensitive-headers:
  routes:
    oauth2-routing:
      path: /oauth2-service/**
      serviceId: oauth2-service
    member-routing:
      path: /member-service/**
      serviceId: member-service
    orders-routing:
      path: /orders-service/**
      serviceId: orders-service
    product-routing:
      path: /product-service/**
      serviceId: product-service

ribbon:
  eager-load:
    enabled: true
    clients: oauth2-service,member-service,orders-service,product-service
Copy the code

The following are two configuration file configuration methods. You can select the configuration that is beneficial to your project as required.

  • Specify the URL type (routes configured in this way are not executed as Hystrix commands, and the Ribbon cannot be used to load balance multiple urls) :
In this configuration, member-routing only gives the route a name, which can be arbitrarily named. Zuul: routes: member-routing: url: http://localhost:10801/ # Specifies the url path: /member-service/** # specifies the pathCopy the code
  • Specify serviceId (this configuration works with Nacos and Hystrix is automatically enabled for routing) :
In this configuration, member-routing only gives the route a name, which can be arbitrarily named. Zuul: routes: member-routing: serviceId: member-service # Specifies the serviceId path: /member-service/** # specifies the pathCopy the code

One of the drawbacks of this configuration is that if you use all the default parameters, you will always get a Hystrix timeout error on every first request.

{"timestamp": "2021-02-18T08:08:38.183+0000", "status": 504, "error": "Gateway Timeout", "message": "com.netflix.zuul.exception.ZuulException: Hystrix Readed time out" }Copy the code

According to the online information, the Ribbon was lazy to load, and Hystrix took too long, resulting in a meltdown. Zuul provides different timeout parameters for the two configurations, which are available on zuul’s website but not detailed here. At present, an effective solution is as follows:

zuul:
    host:
      socket-timeout-millis: 60000
      connect-timeout-millis: 60000

ribbon:
  eager-load:
    enabled: true
  ReadTimeout: 60000
  ConnectTimeout: 60000

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 60000
Copy the code

With the configuration complete, we can compare the requested URL (if the microservice network is physically isolated, then the request can only go through the gateway) :

  • Oauth2-service access request:

No gateway:

POST http://localhost:10800/oauth/token
Copy the code

Bring the gateway:

POST http://localhost:8080/oauth2-service/oauth/token
Copy the code
  • Access request to member-service:

No gateway:

GET http://localhost:10801/api/member/hello
Copy the code

Bring the gateway:

GET http://localhost:8080/member-service/api/member/hello
Copy the code

3.2. Test Zuul to integrate Oauth2 certification results

Request token from Oauth2 authentication center (server) :

# # # # to Oauth2 authentication center (server) request token POST at http://localhost:8080/oauth2-service/oauth/token? grant_type=password&username=admin&password=123456&client_id=app-client&client_secret=client-secret-8888&scope=all Accept: */* Cache-Control: no-cacheCopy the code

Get the request result:

{ "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsib3JkZXJzLXNlcnZpY2UiLCJnYXRld2F5LXNlcnZpY2UiLCJtZW1iZXItc2VydmljZSIsIn Byb2R1Y3Qtc2VydmljZSJdLCJ1c2VyX25hbWUiOiJhZG1pbiIsImp3dC1leHQiOiJKV1Qg5omp5bGV5L-h5oGvIiwic2NvcGUiOlsiYWxsIl0sImV4cCI6MT YxMjg1ODQxNywiYXV0aG9yaXRpZXMiOlsiUk9MRV9BRE1JTiJdLCJqdGkiOiJiMGQ5ZTI1Yy1jZGE3LTQ4MDctOWJmZS02ZjcyYjM4NGVhNTMiLCJjbGllbn RfaWQiOiJhcHAtY2xpZW50In0.w4M9zCahAVISQ_wfKdkT6n9Aaw6kFtoh5HmCJ_uy-vU", "token_type": "bearer", "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsib3JkZXJzLXNlcnZpY2UiLCJnYXRld2F5LXNlcnZpY2UiLCJtZW1iZXItc2VydmljZSIsIn Byb2R1Y3Qtc2VydmljZSJdLCJ1c2VyX25hbWUiOiJhZG1pbiIsImp3dC1leHQiOiJKV1Qg5omp5bGV5L-h5oGvIiwic2NvcGUiOlsiYWxsIl0sImF0aSI6Im IwZDllMjVjLWNkYTctNDgwNy05YmZlLTZmNzJiMzg0ZWE1MyIsImV4cCI6MTYxMjkyMzIxNywiYXV0aG9yaXRpZXMiOlsiUk9MRV9BRE1JTiJdLCJqdGkiOi IzZmQ2MWM4ZS1kNTcyLTQ0YjYtYjViNC0zMzc3ODQ5NjY4YmQiLCJjbGllbnRfaWQiOiJhcHAtY2xpZW50In0.WxisDVLUlfP45pepc4sQM1M7UCvzsET0O8 JvF11tKAI", "expiRES_in ": 7199, "scope": "all"," jwT-ext ": "JWT extension info ", "jTI ":" b0d9e25C-cDA7-4807-9BFE-6f72b384ea53 "}Copy the code

Request data from Oauth2 resource service (client) :

Request without token:

# # # # to Oauth2 resources service (client) request data GET http://localhost:8080/member-service/api/member/hello Accept: * / * cache-control: no-cacheCopy the code

Get the request result:

{
  "error": "unauthorized",
  "error_description": "Full authentication is required to access this resource"
}
Copy the code

Request with correct token:

# # # # to Oauth2 resources service (client) request data GET http://localhost:8080/member-service/api/member/hello Accept: * / * cache-control: no-cache Authorization: bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsib3JkZXJzLXNlcnZpY2UiLCJnYXRld2F5LXNlcnZpY2UiLCJtZW1iZXItc2VydmljZSIsInB yb2R1Y3Qtc2VydmljZSJdLCJ1c2VyX25hbWUiOiJhZG1pbiIsImp3dC1leHQiOiJKV1Qg5omp5bGV5L-h5oGvIiwic2NvcGUiOlsiYWxsIl0sImV4cCI6MTY xMjg1ODQxNywiYXV0aG9yaXRpZXMiOlsiUk9MRV9BRE1JTiJdLCJqdGkiOiJiMGQ5ZTI1Yy1jZGE3LTQ4MDctOWJmZS02ZjcyYjM4NGVhNTMiLCJjbGllbnR faWQiOiJhcHAtY2xpZW50In0.w4M9zCahAVISQ_wfKdkT6n9Aaw6kFtoh5HmCJ_uy-vUCopy the code

Get the request result:

Hello, Member! Hello, Product! Hello, Orders! 
Copy the code

3.3. Zuul integrated Oauth2 authentication analysis

Authentication and authorization are two different steps. We have completed the authentication part, the authorization part refers to the specific URL permissions, this thing is more business specific code will not paste, but can provide you with ideas.

Why do you say that authorized URL is a strong business? I believe you have seen many examples online, the simplest is the RBAC0 (Role-based Access Control) model five table structure (user table – Role table – resource table – user Role relationship – Role resource relationship), the company organization is nothing more than a group of users, the basic appearance is similar. We learn from each other at the same time might as well stop to think, enterprise application is not a set of models to add, delete, change and check, if my micro services want to maintain a set of authority system? My so-called URL is not maintained by a single large system, but I want each micro-service to maintain a set of URL permission system, so that the URL authorization logic written in the gateway seems complicated, coupled and useless. The most appropriate solution is for the gateway to handle authentication and the UPMS (User Permissions Management System) subsystem to handle authorization.

UserDetailsService from oAuth2-service in the previous article:

@Slf4j
@Component(value = "herringUserDetailsService")
public class HerringUserDetailsService implements UserDetailsService {

    @Resource
    private PasswordEncoder passwordEncoder;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        log.info("username is:" + username);
        // 查询数据库操作
        if (!username.equals("admin")) {
            throw new UsernameNotFoundException("the user is not found");
        } else {
            // 用户角色也应在数据库中获取
            String role = "ROLE_ADMIN";
            List<SimpleGrantedAuthority> authorities = new ArrayList<>();
            authorities.add(new SimpleGrantedAuthority(role));
            // 线上环境应该通过用户名查询数据库获取加密后的密码
            String password = passwordEncoder.encode("123456");
            return new org.springframework.security.core.userdetails.User(username, password, authorities);
        }
    }

}
Copy the code

We can take this part of logic out of an independent UPMS (User Permissions Management System) System and briefly introduce the ROLE-based Access Control (RBAC) model:

RBAC0 model:

This is the most basic and core model of permissions, which includes users/roles/permissions. Users and roles are many-to-many, and roles and permissions are many-to-many.

User: initiates an operation. Users can be classified into 2B and 2C users by type. They can be background management system users, OA system internal employees, or C-terminal users, such as Aliyun users.

Role: Functions as a bridge connecting users and rights. Each role can be associated with multiple rights. If a user is associated with multiple roles, the user has multiple rights of multiple roles. One might ask why users don’t associate permissions directly? In a system with a small user base, such as a small system with 20 people, the administrator can directly associate users with permissions. The workload is not large, so it is all right to select a user and check the required permissions. However, in the actual enterprise system, the user base is relatively large, and many of them have the same permissions, which are ordinary access permissions. If the administrator grants authorization to 100 or more people, the workload will be huge. This introduces the concept of “Role”. A Role can be associated with multiple users, and the administrator only needs to assign the Role to the user, so that the user can have all the permissions under the Role. In this way, the design not only improves efficiency, but also greatly expands.

Permission: refers to the resources that users can access, including page permission, operation permission, and data permission:

  • Page permission: the page that a user can see after logging in to the system is controlled by the menu. The menu includes the first-level menu and the second-level menu. As long as the user has the permission of the first-level menu and the second-level menu, the user can access the page.
  • Operation permission: function buttons on the page, including view, add, modify, delete, and review. When a user clicks the delete button, the background verifies whether all permissions under the user role include the delete permission. If yes, the user can proceed to the next step. Some system requirements “visible to operation”, meaning if the page can see the button operation, so the user can operate, in order to achieve this requirement, there is need to cooperate, the front-end front-end development of the user permission information cache, judge whether the user containing the permissions on the page, if you have, will display the button, if not, just hide this button. The user experience is improved to some extent, but it is optional to do so in real scenarios.
  • Data permissions: Data access is the user on the same page to see the data is different, such as the user data under the finance department can only see the department, purchasing department only look at purchasing data, in a few large companies, there are a lot of cities in China and branch, such as user login system can only see the data of hangzhou, hangzhou Shanghai users can only see the data, Generally, the solution is to associate the data with specific organizational structure. For example, when the user is authorized, the user selects a role and binds to the organization such as finance department or Hefei Branch, so the user has the data permission of finance Department or Hefei Branch under the role.

This is the core design and model analysis of RBAC, also known as RBAC0, which provides extended patterns based on the core concepts. Including RBAC1, RBAC2, RBAC3 models.

RBAC1 model:

This model introduces the concept of Hierarchical Role, that is, roles have Hierarchical relationships. The Hierarchical relationships among roles can be divided into general and restricted Hierarchical relationships. The general inheritance relationship only requires that the role inheritance relationship be an absolute partial order relationship, allowing multiple inheritance between roles. The restricted inheritance relationship further requires that the role inheritance relationship be a tree structure to achieve single inheritance between roles. This design can group and layer roles, which simplifies permission management to a certain extent.

RBAC2 model:

On the basis of the core model, the role constraint control is carried out. The RBAC2 model adds the separation of responsibilities, which specifies the mandatory rules that should be followed when the rights are assigned to the role or the role is assigned to the user, and when the user activates a role at a certain moment. Separation of responsibility includes static separation of responsibility and dynamic separation of responsibility. Mainly includes the following constraints:

  • Mutually exclusive roles: A user can be assigned to only one role in a set of mutually exclusive roles, which supports the principle of responsibility separation. A mutually exclusive role refers to two roles whose rights restrict each other. For example, the financial Department has two roles, accounting and auditor, which are mutually exclusive, so users cannot have both roles, which reflects the principle of separation of responsibilities.
  • Cardinality constraints: Limits on the number of users assigned to a role; The number of roles a user can have is limited; The number of access permissions corresponding to a role should also be limited to control the allocation of advanced permissions in the system.
  • Prerequisite Role: To obtain an upper-level role, a user must obtain the lower-level role.

RBAC3 model:

The most comprehensive permission management, based on RBAC0, RBAC1 and RBAC2 are integrated.

Spring Cloud Alibaba combat (1) Prepare for Spring Cloud Alibaba combat (2) Nacos Article Spring Cloud Alibaba combat (3) Sentinel article Spring Cloud Alibaba Spring Cloud Alibaba (Zuul) Spring Cloud Alibaba (Zuul Cloud Alibaba Combat (8) SkyWalking

GitHub address: github.com/D2C-Cai/her…