related

  1. Spring Cloud Series 1 – Service Registration and Discovery Eureka

  2. Spring Cloud – Client calls Rest + Ribbon

  3. Spring Cloud Combat Series iii – Declarative client Feign

  4. Spring Cloud Series iv – Fuse Hystrix

  5. Spring Cloud Combat Series 5 – Service Gateway Zuul

  6. Spring Cloud Deployment Series (6) – Distributed Configuration center Spring Cloud Config

  7. Spring Cloud Combat Series (7) – Service Link Tracking Spring Cloud Sleuth

  8. Spring Cloud Combat Series (8) – Micro service monitoring Spring Boot Admin

  9. Spring Cloud OAuth 2.0

  10. Single sign-on JWT and Spring Security OAuth

preface

OAuth 2.0 is an intermediate layer between user resources and third-party applications. It separates resources from third-party applications so that third-party applications cannot directly access resources, thus protecting resources. In order to access this restricted resource, third-party applications (clients) need to provide credentials at the time of access.

The body of the

1. Introduction to OAuth 2.0

During authentication and authorization, the following roles are involved:

  • Service provider: Authorization Server

  • Resource owner: Resource Server

  • Client: Client

The authentication process of OAuth 2.0 is shown as follows:

  1. The user (resource holder) opens the client, which asks the user for authorization.

  2. The user agrees to authorize.

  3. The client applies for authorization from the authorization server.

  4. The authorization server authenticates the client, including user information, and authorizes the token after successful authentication.

  5. After the client obtains the token, it requests resources from the resource server with the token.

  6. The resource server verifies that the token is correct and issues resources to the client.

OAuth2 Provider roles are divided into Authorization Server (Authorization Service) and Resource Service (Resource Service), usually not in the same Service. One Authorization Service may correspond to multiple Resource Services. Spring OAuth2.0 is used in conjunction with Spring Security. All requests are handled by the Spring MVC controller and intercepted by a series of Spring Security filters.

There are two endpoints in the Spring Security filter chain that are used to obtain authentication and Authorization from the Authorization Service.

  • Endpoints for authorization: default to /oauth/authorize.

  • Endpoint used to get the token: default is /oauth/token.

2. Create a local database

Client information can be stored in a database so that data for client information can be updated in real time by changing the database. Spring OAuth2 has designed the tables of the database and is immutable. Start by importing the following DDL into the database.

SET NAMES utf8;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for `clientdetails`
-- ----------------------------
DROP TABLE IF EXISTS `clientdetails`;
CREATE TABLE `clientdetails` (
  `appId` varchar(128) NOT NULL.`resourceIds` varchar(256) DEFAULT NULL.`appSecret` varchar(256) DEFAULT NULL.`scope` varchar(256) DEFAULT NULL.`grantTypes` varchar(256) DEFAULT NULL.`redirectUrl` varchar(256) DEFAULT NULL.`authorities` varchar(256) DEFAULT NULL.`access_token_validity` int(11) DEFAULT NULL.`refresh_token_validity` int(11) DEFAULT NULL.`additionalInformation` varchar(4096) DEFAULT NULL.`autoApproveScopes` varchar(256) DEFAULT NULL,
  PRIMARY KEY (`appId`))ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Table structure for `oauth_access_token`
-- ----------------------------
DROP TABLE IF EXISTS `oauth_access_token`;
CREATE TABLE `oauth_access_token` (
  `token_id` varchar(256) DEFAULT NULL.`token` blob.`authentication_id` varchar(128) NOT NULL.`user_name` varchar(256) DEFAULT NULL.`client_id` varchar(256) DEFAULT NULL.`authentication` blob.`refresh_token` varchar(256) DEFAULT NULL,
  PRIMARY KEY (`authentication_id`))ENGINE=InnoDB DEFAULT CHARSET=utf8;


-- ----------------------------
-- Table structure for `oauth_approvals`
-- ----------------------------
DROP TABLE IF EXISTS `oauth_approvals`;
CREATE TABLE `oauth_approvals` (
  `userId` varchar(256) DEFAULT NULL.`clientId` varchar(256) DEFAULT NULL.`scope` varchar(256) DEFAULT NULL.`status` varchar(10) DEFAULT NULL.`expiresAt` datetime DEFAULT NULL.`lastModifiedAt` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Table structure for `oauth_client_details`
-- ----------------------------
DROP TABLE IF EXISTS `oauth_client_details`;
CREATE TABLE `oauth_client_details` (
  `client_id` varchar(256) NOT NULL.`resource_ids` varchar(256) DEFAULT NULL.`client_secret` varchar(256) DEFAULT NULL.`scope` varchar(256) DEFAULT NULL.`authorized_grant_types` varchar(256) DEFAULT NULL.`web_server_redirect_uri` varchar(256) DEFAULT NULL.`authorities` varchar(256) DEFAULT NULL.`access_token_validity` int(11) DEFAULT NULL.`refresh_token_validity` int(11) DEFAULT NULL.`additional_information` varchar(4096) DEFAULT NULL.`autoapprove` varchar(256) DEFAULT NULL,
  PRIMARY KEY (`client_id`))ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Table structure for `oauth_client_token`
-- ----------------------------
DROP TABLE IF EXISTS `oauth_client_token`;
CREATE TABLE `oauth_client_token` (
  `token_id` varchar(256) DEFAULT NULL.`token` blob.`authentication_id` varchar(128) NOT NULL.`user_name` varchar(256) DEFAULT NULL.`client_id` varchar(256) DEFAULT NULL,
  PRIMARY KEY (`authentication_id`))ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Table structure for `oauth_code`
-- ----------------------------
DROP TABLE IF EXISTS `oauth_code`;
CREATE TABLE `oauth_code` (
  `code` varchar(256) DEFAULT NULL.`authentication` blob
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Table structure for `oauth_refresh_token`
-- ----------------------------
DROP TABLE IF EXISTS `oauth_refresh_token`;
CREATE TABLE `oauth_refresh_token` (
  `token_id` varchar(256) DEFAULT NULL.`token` blob.`authentication` blob
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


-- ----------------------------
-- Table structure for `role`
-- ----------------------------
DROP TABLE IF EXISTS `role`;
CREATE TABLE `role` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  PRIMARY KEY (`id`))ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;


-- ----------------------------
-- Table structure for `user`
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `password` varchar(255) DEFAULT NULL.`username` varchar(255) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `UK_sb8bbouer5wak8vyiiy4pf2bx` (`username`))ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;


-- ----------------------------
-- Table structure for `user_role`
-- ----------------------------
DROP TABLE IF EXISTS `user_role`;
CREATE TABLE `user_role` (
  `user_id` bigint(20) NOT NULL.`role_id` bigint(20) NOT NULL.KEY `FKa68196081fvovjhkek5m97n3y` (`role_id`),
  KEY `FK859n2jvi8ivhui0rl0esws6o` (`user_id`),
  CONSTRAINT `FK859n2jvi8ivhui0rl0esws6o` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`),
  CONSTRAINT `FKa68196081fvovjhkek5m97n3y` FOREIGN KEY (`role_id`) REFERENCES `role` (`id`))ENGINE=InnoDB DEFAULT CHARSET=utf8;


SET FOREIGN_KEY_CHECKS = 1;
Copy the code

3. Create a Maven project

Using Maven’s multi-module project structure, create an empty Maven project and configure the Spring Boot version 1.5.3.RELEASE in the pom. XML file in the root directory. The Spring Cloud version is dalston.release and the complete code 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 http://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>1.5.3. RELEASE</version>
        <relativePath/>
    </parent>

    <modules>
        <module>eureka-server</module>
        <module>service-auth</module>
        <module>service-hi</module>
    </modules>

    <groupId>io.github.ostenant.springcloud</groupId>
    <artifactId>spring-cloud-oauth2-example</artifactId>
    <version>0.0.1 - the SNAPSHOT</version>
    <name>spring-cloud-oauth2-example</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Dalston.RELEASE</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <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>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>
Copy the code

4. Create Eureka Server

4.1. Create an application module

Create a new Eureka-server module, add eureka dependencies, and specify the parent node of pom.xml 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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>io.github.ostenant.springcloud</groupId>
    <artifactId>eureka-server</artifactId>
    <version>0.0.1 - the SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>eureka-server</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>io.github.ostenant.springcloud</groupId>
        <artifactId>spring-cloud-oauth2-example</artifactId>
        <version>0.0.1 - the SNAPSHOT</version>
    </parent>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka-server</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>
Copy the code

4.2. The configuration application. Yml

Configure the eureka server information in the application. Yml configuration file of the Eureka server module:

server:
  port: 8761
eureka:
  instance:
    hostname: localhost
  client:
    registerWithEureka: false
    fetchRegistry: false
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
Copy the code

4.3. Configure the application startup class

Finally, add @enableEurekaserver annotation to the application startup class to enable the EurekaServer function.

@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {

    public static void main(String[] args) { SpringApplication.run(EurekaServerApplication.class, args); }}Copy the code

5. Create the Uaa authorization service

5.1. Create an Application module

Create a new service-auth module and add the following dependencies as Uaa (authorization service). The complete code 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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>io.github.ostenant.springcloud</groupId>
    <artifactId>service-auth</artifactId>
    <version>0.0.1 - the SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>service-auth</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>io.github.ostenant.springcloud</groupId>
        <artifactId>spring-cloud-oauth2-example</artifactId>
        <version>0.0.1 - the SNAPSHOT</version>
    </parent>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth2</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>
Copy the code

When you open the spring-Cloud-starter-OAuth2 dependency package, you can see that it already integrates the following three starter dependencies:

  • spring-cloud-starter-security

  • spring-security-oauth2

  • spring-security-jwt

5.2. The configuration application. Yml

Application. Yml in the service-oauth module completes the following configuration:

spring:
  application:
    name: service-auth
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/spring-cloud-auth? useUnicode=true&characterEncoding=utf8&characterSetResults=utf8
    username: root
    password: 123456
  jpa:
    hibernate:
      ddl-auto: update
    show-sql: true

server:
  context-path: /uaa
  port: 5000

security:
  oauth2:
    resource:
      filter-order: 3
# basic:
# enabled: false

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
Copy the code

Configure security. Oauth2. Resource. The filter – the order for 3, in the Spring the Boot 1.5 x version before, can omit this configuration.

5.3. Configure security authentication

Auth-service is also a resource service. Spring Security needs to be introduced into auth-Service and relevant configurations need to be completed. In this way, auth-service resources are protected.

WebSecurityConfig.java

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private UserServiceDetail userServiceDetail;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // @formatter:off
        http.authorizeRequests().anyRequest().authenticated()
            .and()
            .csrf().disable();
        // @formatter:on
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userServiceDetail).passwordEncoder(new BCryptPasswordEncoder());
    }

    @Override
    public @Bean AuthenticationManager authenticationManagerBean(a) throws Exception {
        return super.authenticationManagerBean(); }}Copy the code

UserServiceDetail.java

@Service
public class UserServiceDetail implements UserDetailsService {
    @Autowired
    private UserRepository userRepository;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        returnuserRepository.findByUsername(username); }}Copy the code

To configure the relational mapping class User for the table, implement the UserDetails interface:

@Entity
public class User implements UserDetails.Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false, unique = true)
    private String username;

    @Column
    private String password;

    @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @JoinTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"),
            inverseJoinColumns = @JoinColumn(name = "role_id", referencedColumnName = "id"))
    private List<Role> authorities;

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return authorities;
    }

    // setter getter

    @Override
    public boolean isAccountNonExpired(a) {
        return true;
    }

    @Override
    public boolean isAccountNonLocked(a) {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired(a) {
        return true;
    }

    @Override
    public boolean isEnabled(a) {
        return true; }}Copy the code

GrantedAuthority = GrantedAuthority = GrantedAuthority = GrantedAuthority

@Entity
public class Role implements GrantedAuthority {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String name;

    // setter getter

    @Override
    public String getAuthority(a) {
        return name;
    }

    @Override
    public String toString(a) {
        returnname; }}Copy the code

UserRepository.java

public interface UserRepository extends JpaRepository<User.Long> {
    User findByUsername(String username);
}
Copy the code

5.4. Configure the Authentication Server

Configure the authentication Server, using the @ EnableAuthorizationServer annotations open Authorization Server, provides the function of authentication and Authorization.

@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationConfig extends AuthorizationServerConfigurerAdapter {

    // Store the Token in memory
    // private TokenStore tokenStore = new InMemoryTokenStore();
    private TokenStore tokenStore = new JdbcTokenStore(dataSource);

    @Autowired
    @Qualifier("dataSource")
    private DataSource dataSource;

    @Autowired
    @Qualifier("authenticationManagerBean")
    private AuthenticationManager authenticationManager;

    @Autowired
    private UserServiceDetail userServiceDetail;

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        // Store the client information in memory
        clients.inMemory()
              // create a client named browser
              .withClient("browser")
              // Configure the authentication type
              .authorizedGrantTypes("refresh_token"."password")
              // Set the client domain to "UI"
              .scopes("ui")
              .and()
              .withClient("service-hi")
              .secret("123456")
              .authorizedGrantTypes("client_credentials"."refresh_token"."password")
              .scopes("server");
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        // Configure the Token storage mode
        endpoints.tokenStore(tokenStore)
                // Inject the bean configured with WebSecurityConfig
                .authenticationManager(authenticationManager)
                // Read the user's authentication information
                .userDetailsService(userServiceDetail);
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
        // Requests for tokens are no longer intercepted
        oauthServer.tokenKeyAccess("permitAll()")
                 // Verify To obtain Token authentication information
                .checkTokenAccess("isAuthenticated()"); }}Copy the code

5.5. Start Resource Server

In the application startup class, use the @enableresourceserver annotation to enable the resource service. The application needs to expose the API interface for obtaining the token.

@EnableEurekaClient
@EnableResourceServer
@SpringBootApplication
public class ServiceAuthApplication {

    public static void main(String[] args) { SpringApplication.run(ServiceAuthApplication.class, args); }}Copy the code

In this example, RemoteTokenService is used to verify the token. If other resource services need to authenticate tokens, they need to remotely invoke the AUTHENTICATION TOKEN API exposed by the authorization service.

@RestController
@RequestMapping("/users")
public class UserController {

    @RequestMapping(value = "/current", method = RequestMethod.GET)
    public Principal getUser(Principal principal) {
        returnprincipal; }}Copy the code

6. Write the service-hi resource service

6.1. Creating an Application Module

Create a new service-hi module that serves as a resource service. Introduce the following dependencies in the POM.xml file:

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>io.github.ostenant.springcloud</groupId>
    <artifactId>service-hi</artifactId>
    <version>0.0.1 - the SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>service-hi</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>io.github.ostenant.springcloud</groupId>
        <artifactId>spring-cloud-oauth2-example</artifactId>
        <version>0.0.1 - the SNAPSHOT</version>
    </parent>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-feign</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth2</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>
Copy the code

6.2. The configuration application. Yml

Configure the OAuth Client information configured in service-auth:

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
server:
  port: 8762
spring:
  application:
    name: service-hi
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/spring-cloud-auth? useUnicode=true&characterEncoding=utf8&characterSetResults=utf8
    username: root
    password: 123456
  jpa:
    hibernate:
      ddl-auto: update
    show-sql: true

security:
  oauth2:
    resource:
      user-info-uri: http://localhost:5000/uaa/users/current Get the user information of the current Token
    client:
      clientId: service-hi
      clientSecret: 123456
      accessTokenUri: http://localhost:5000/uaa/oauth/token # access Token
      grant-type: client_credentials,password
      scope: server
Copy the code

6.3. Configure Resource Server

As a Resource server, the server-HI module needs to configure the Resource Server. The configuration code is as follows:

@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResourceServerConfigurer extends ResourceServerConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
              // open to the user registered URL
              .antMatchers("/user/registry").permitAll() .anyRequest().authenticated(); }}Copy the code

6.4. Configure the OAuth2 Client

@Configuration
@EnableOAuth2Client
@EnableConfigurationProperties
public class OAuth2ClientConfig {

    @Bean
    @ConfigurationProperties(prefix = "security.oauth2.client")
    public ClientCredentialsResourceDetails clientCredentialsResourceDetails(a) {
        // Configure the protected resource information
        return new ClientCredentialsResourceDetails();
    }

    @Bean
    public RequestInterceptor oauth2FeignRequestInterceptor(a){
        // Configure an interceptor that creates an AccessTokenRequest type bean in the Request field for each incoming request.
        return new OAuth2FeignRequestInterceptor(
                        new DefaultOAuth2ClientContext(),
                        clientCredentialsResourceDetails());
    }

    @Bean
    public OAuth2RestTemplate clientCredentialsRestTemplate(a) {
        // Used to request a token from the authentication server service
        return newOAuth2RestTemplate(clientCredentialsResourceDetails()); }}Copy the code

6.5. Create a User registration interface

Copy user-java and userRepository. Java from the service-Auth module to the service-hi module. Create a UserService to create a user and encrypt the user password.

UserService.java

@Service
public class UserService {
   private static final BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();

   @Autowired
   private UserRepository userRepository;

   public User create(String username, String password) {
      User user = new User();
      user.setUsername(username);
      String hash = encoder.encode(password);
      user.setPassword(hash);
      returnuserRepository.save(user); }}Copy the code

UserController.java

@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;

    @RequestMapping(value = "/registry", method = RequestMethod.POST)
    public User createUser(@RequestParam("username") String username,
                           @RequestParam("password") String password) {
        returnuserService.create(username,password); }}Copy the code

6.6. Create a Resource Service Interface

@RestController
public class HiController {
    private static final Logger LOGGER = LoggerFactory.getLogger(HiController.class);

    @Value("${server.port}")
    private String port;

    /** * does not require any permissions, as long as the Token in the Header is correct */
    @RequestMapping("/hi")
    public String hi(a) {
        return "hi : " + ",i am from port: " + port;
    }

    /** * requires the ROLE_ADMIN permission */
    @PreAuthorize("hasAuthority('ROLE_ADMIN')")
    @RequestMapping("/hello")
    public String hello(a) {
        return "hello you!";
    }

    /** * Obtain information about the current authenticated user */
    @GetMapping("/getPrinciple")
    public OAuth2Authentication getPrinciple(OAuth2Authentication oAuth2Authentication, Principal principal, Authentication authentication){
        LOGGER.info(oAuth2Authentication.getUserAuthentication().getAuthorities().toString());
        LOGGER.info(oAuth2Authentication.toString());
        LOGGER.info("principal.toString()" + principal.toString());
        LOGGER.info("principal.getName()" + principal.getName());
        LOGGER.info("authentication:" + authentication.getAuthorities().toString());

        returnoAuth2Authentication; }}Copy the code

6.6. Configure the startup class of the application

@EnableEurekaClient
@SpringBootApplication
public class ServiceHiApplication {

    public static void main(String[] args) { SpringApplication.run(ServiceHiApplication.class, args); }}Copy the code

Start eureka-service, service-auth, and service-hi in sequence.

7. Use PostMan authentication

  • To register a user, return the registration success message

  • The value is obtained from the authentication server in password modetoken

  • Accessing resource Services/hi, don’t need permission, justtokenYou can correct

  • Accessing resource Services/hello, prompt needROLE_ADMINpermissions

  • Failed to access databaseroleList, addPermission information ROLE_ADMINAnd then inuser_roleTable association is accessed again

conclusion

There is still room for improvement in this case. For example, add a login interface to the resource server that is not protected by Spring Security. After the login is successful, service-hi remotely invokes auth-service to obtain the token and returns the token to the browser. All subsequent requests of the browser must carry the token.

The drawback of this architecture is that each request requires a remote invocation of the service-Auth service from within the resource service to verify the correctness of the token and the permissions of the user corresponding to the token, adding an additional internal request overhead. If the concurrency is high, service-Auth needs to be deployed in a cluster and needs to be cached. Therefore, the best solution is to use Spring Security OAuth2 and JWT together to realize the authentication and authorization of Spring Cloud microservice system.

reference

  • An In-depth Understanding of Spring Cloud and Microservice Construction by Zhipeng Fang

Welcome to pay attention to the technical public number: Zero one Technology Stack

This account will continue to share learning materials and articles on back-end technologies, including virtual machine basics, multithreaded programming, high-performance frameworks, asynchronous, caching and messaging middleware, distributed and microservices, architecture learning and progression.