Build spring cloud microservice framework: 4. Authentication of spring security OAuth service interface

Time:2020-9-24

Build microservice framework (service interface authentication)

We can build external interfaces through spring cloud. Now let’s introduce how to use oauth2 to authenticate interfaces.

Source address of this paper: build microservice framework (service interface authentication)

GitHub address: Squid


introduce

Oauth2 introduces too many examples on the Internet. It is a standard of authorization simply.

  • Oauth2 currently has four authorization mechanisms:

Authorization code

The authorization code mode is mostly used for Internet login scenarios. For example, in Jingdong Mall website, QQ number is used for authorization login

Build spring cloud microservice framework: 4. Authentication of spring security OAuth service interface

Simplify mode

Generally, it is rarely used. At present, there is no code implementation of this mode, so we still do not describe it, so as to avoid mistakes

Resource owner password credentials

Password mode is used very much for the general enterprise B / S architecture system. After all, the user name and password have been stored in the system, and the password mode is to provide the user name and password. The client uses this information to ask for authorization from the service provider (i.e., the system developed by the enterprise).

Client credentials

Client mode is mostly used for the use of third-party interfaces. Assign a secret to the other party and use the other party to access_ Get token.

  • Key terms Description:

    • client_ ID: the ID of the client.
    • access_ Token: the token returned after successful authorization.
    • expires_ In: expiration time.
    • refresh_ token : access_ Token is about to expire, or access_ Token is missing, refresh can be used_ Token reacquives.
    • Scope: the scope of this application.
    • grant_ Type: the type of authorization. Fill in the noun defined by the corresponding authorization mechanism.

This integration isSpring Security OAuth, the integrated project only supportsPassword modeandClient modeTwo kinds.


Using spring security OAuth

When integrating OAuth, we need to have the following environment:

Mysql5.7+

MySQL is used to record the necessary information of OAuth:client_id、clien_secret、grant、scope, SQL script address: oauth2.sql

Redis

Redis is used to controlaccess_tokenThe validity period of.

New project

First of all, we will build a new one under the original projectsquid-oatuh2The following Maven dependencies are introduced:

   <dependency>
       <groupId>org.springframework.security.oauth</groupId>
       <artifactId>spring-security-oauth2</artifactId>
       <version>2.3.3.RELEASE</version>
   </dependency>
   
   <dependency>
       <groupId>org.springframework.cloud</groupId>
       <artifactId>spring-cloud-starter-security</artifactId>
   </dependency>

   <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-data-redis</artifactId>
   </dependency>

   <dependency>
       <groupId>mysql</groupId>
       <artifactId>mysql-connector-java</artifactId>
   </dependency>
   
   <dependency>
       <groupId>org.springframework</groupId>
       <artifactId>spring-jdbc</artifactId>
   </dependency>

   <dependency>
       <groupId>com.alibaba.cloud</groupId>
       <artifactId>spring-cloud-alibaba-nacos-discovery</artifactId>
   </dependency>

   <dependency>
       <groupId>com.alibaba.cloud</groupId>
       <artifactId>spring-cloud-alibaba-nacos-config</artifactId>
   </dependency>

After introducing dependencies, we begin to write code that uses OAuth. For convenience, I will first take a screenshot of my project:

Build spring cloud microservice framework: 4. Authentication of spring security OAuth service interface

Next, the code:

  • AuthResourceConfig
@EnableResourceServer
    @Configuration
    public class AuthResourceConfig extends ResourceServerConfigurerAdapter {
    
        @Autowired
        RedisConnectionFactory redisConnectionFactory;
    
    //    @Autowired
    //    DataSource dataSource;
    
        @Override
        public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
            super.configure(resources);
        }
    
        @Override
        public void configure(HttpSecurity http) throws Exception {
            http.
                    csrf().disable()
                    .authorizeRequests().anyRequest().authenticated()
                    .and()
                    .httpBasic();
        }
    
    //    @Bean
    //    ResourceServerTokenServices resourceServerTokenServices() {
    //        RemoteTokenServices tokenServices = new RemoteTokenServices();
    //        tokenServices.setCheckTokenEndpointUrl("http://localhost:8081/oauth/check_token");
    //        tokenServices.setAccessTokenConverter(accessTokenConverter());
    //        return tokenServices;
    //    }
    
        @Bean
        public AccessTokenConverter accessTokenConverter() {
            return new DefaultAccessTokenConverter();
        }
    
        @Bean
        RedisTokenStore redisTokenStore() {
            return new RedisTokenStore(redisConnectionFactory);
        }
    
    //    @Bean
    //    ClientDetailsService clientDetailsService() {
    //        return new JdbcClientDetailsService(dataSource);
    //    }
    
        @Bean
        @Primary
        DefaultTokenServices defaultTokenServices() {
            DefaultTokenServices tokenServices = new DefaultTokenServices();
            tokenServices.setTokenStore(redisTokenStore());
    //        tokenServices.setSupportRefreshToken(true);
    //        tokenServices.setClientDetailsService(clientDetailsService());
    //         tokenServices.setAccessTokenValiditySeconds (60 * 60 * 12); // the validity period of token is user-defined. The default is 12 hours
    //         tokenServices.setRefreshTokenValiditySeconds (60 * 60 * 24 * 7); // the default is 30 days, which is modified here
            return tokenServices;
        }
    
    }

As a resource authorization module, authresourceconfig appears more often in business module projects. It does resource authorization. Each microservice module will be defined as a resource, while resource request needs to be checked every timeaccess_token
This class can appear in any microservice project.

  • AuthServerConfig
@Configuration
@EnableAuthorizationServer
public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {
    @Autowired
    RedisConnectionFactory redisConnectionFactory;

    @Autowired
    DataSource dataSource;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private UserDetailsServiceImpl userServices;

    @Bean
    RedisTokenStore redisTokenStore() {
        return new RedisTokenStore(redisConnectionFactory);
    }

    @Bean
    ClientDetailsService clientDetailsService() {
        return new JdbcClientDetailsService(dataSource);
    }

    @Bean
    @Primary
    DefaultTokenServices defaultTokenServices() {
        DefaultTokenServices tokenServices = new DefaultTokenServices();
        tokenServices.setTokenStore(redisTokenStore());
        tokenServices.setSupportRefreshToken(true);
        tokenServices.setClientDetailsService(clientDetailsService());
        tokenServices.setAccessTokenValiditySeconds (60 * 60 * 12); // the validity period of token is user-defined. The default is 12 hours
        tokenServices.setRefreshTokenValiditySeconds (60 * 60 * 24 * 7); // the default is 30 days, which is modified here
        return tokenServices;
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.tokenKeyAccess("permitAll()");
        security.checkTokenAccess("isAuthenticated()");
        security.allowFormAuthenticationForClients();
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.withClientDetails(clientDetailsService());
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(redisTokenStore()).userDetailsService(userServices).authenticationManager(authenticationManager).tokenServices(defaultTokenServices());
    }
}

Authentication and authorization, as the name implies, you can see the implementation code. What you do is to interact with MySQL and redis, process the key user login information, and define the validity period of the token.

  • WebSecurityConfig
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsServiceImpl userServices;

    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

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

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

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/css/**", "/js/**", "/plugins/**", "/favicon.ico");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
//        http
//                .authorizeRequests()
//                .anyRequest().authenticated()
//                .antMatchers("/oauth/**").permitAll()
//                .and()
//                .csrf().disable();
    }

    public static void main(String[] args) {
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();

        boolean matches = encoder.matches("123456", "$2a$10$cKRbR9IJktfmKmf/wShyo.5.J8IxO/7YVn8twuWFtvPgruAF8gtKq");
        System.out.println(matches);
//        System.out.println(encoder.encode("123456"));
    }
}
  • UserServiceImpl
@Service
public class UserDetailsServiceImpl implements UserDetailsService {

//    @Autowired
//    private SysUserDao sysUserDao;

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {

//        SysUser sysUser = sysUserDao.findByUserName(s);
//
//        if (sysUser == null) {
//Throw new usernamenotfoundexception;
//        }

        return new User(s, "$2a$10$cKRbR9IJktfmKmf/wShyo.5.J8IxO/7YVn8twuWFtvPgruAF8gtKq", new HashSet<>());
    }

}

So far, it has not been introducedSpringDataJPAas well asMyBatils-PlusHere we write the user password to death123456

  • application.yaml
server:
  port: 8081
spring:
  redis:
    host: yanzhenyidai.com
    port: 6379
    password: ****
  datasource:
    url: jdbc:mysql://yanzhenyidai.com:3306/oauth2?useUnicode=true&characterEncoding=utf-8
    username: yanzhenyidai
    password: password
    druid:
      driver-class-name: com.mysql.jdbc.Driver
  main:
    allow-bean-definition-overriding: true
  cloud:
    nacos:
      discovery:
        server-addr: yanzhenyidai.com:8848
  application:
    name: squid-oauth2
    show-sql: true
logging:
  config: classpath:logback.xml
  level:
    org:
      springframework:
        web: info
  • OAuthApplication
@SpringBootApplication
@EnableDiscoveryClient
@RestController
public class OAuthApplication {

    public static void main(String[] args) {
        SpringApplication.run(OAuthApplication.class, args);
    }

    @GetMapping("/test")
    public String test() {
        return "test";
    }

    @RequestMapping("/user")
    public Principal principal(Principal principal) {
        return principal;
    }


}

When everything is done, we start the service to test, and this time we need to usePOSTMAN

Build spring cloud microservice framework: 4. Authentication of spring security OAuth service interface

AuthorizationMediumBasicIs a fixed value, and the subsequent encrypted string is the base64 decryption value of scope + password.

Build spring cloud microservice framework: 4. Authentication of spring security OAuth service interface


summary

Using oauth2 can help us to authenticate and solve the cross domain problem of CSRF. When selecting OAuth, I was worried that it would be very complicated. After all, I had deep experience in using oauth2SpringSecurityThe helplessness of.

reference material:

OAuth-example

Spring-Security-OAuth

A simple explanation of OAuth 2.0

BAELDUNG.com (OAUTH)

Recommended Today

What black technology does the real-time big data platform use behind the glory of the king?

Hello everyone, I’m Xu Zhenwen. Today’s topic is “Tencent game big data service application practice based on Flink + servicemesh”, which is mainly divided into the following four parts: Introduction to background and Solution Framework Real time big data computing onedata Data interface service onefun Microservice & servicemesh 1、 Introduction to the solution framework and […]