Spring Cloud 之 Oauth2

1.创建Eureka服务器

  a.创建SpringBoot工程,依赖选择Eureka Server

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

        ...

    </dependencies>

  b.修改 application.yml 配置

spring:
  application:
    name: eureka-server

server:
  port: 8081

eureka:
  instance:
    hostname: localhost
  client:
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
    fetch-registry: false
    register-with-eureka: false

  c.启动类添加注解@EnableEurekaServer

@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {

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

}

2.创建Oauth2服务器

  a.创建SpringBoot工程,依赖选择Eureka Discovery 、Web、Spring Data Redis、Cloud Oauth2

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth2</artifactId>
        </dependency>

        .....

    </dependencies>

  b.修改 application.yml 配置

spring:
  application:
    name: oauth-client
  redis:
    host: localhost
    database: 0

server:
  port: 8082

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8081/eureka/

  c.创建 AuthorizationServerConfiguration 继承 AuthorizationServerConfigurerAdapter

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

    @Resource
    AuthenticationManager authenticationManager;

    @Resource
    RedisConnectionFactory redisConnectionFactory;

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        String finalSecret = "{bcrypt}" + new BCryptPasswordEncoder().encode("123456");

        // 配置两个客户端,一个用于password认证一个用于client_credentials认证
        clients.inMemory().withClient("client_1")
                .authorizedGrantTypes("client_credentials", "refresh_token")
                .scopes("server")
                .authorities("oauth2")
                .secret(finalSecret)
                .and().withClient("client_2")
                .authorizedGrantTypes("password", "refresh_token")
                .scopes("select")
                .authorities("oauth2")
                .secret(finalSecret);
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(new RedisTokenStore(redisConnectionFactory))
                .authenticationManager(authenticationManager)
                .allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        // 允许表单认证
        security.allowFormAuthenticationForClients();
    }

}

  d.创建 SecurityConfiguration 继承 WebSecurityConfigurerAdapter

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Bean
    @Override
    protected UserDetailsService userDetailsService() {
        //模拟用户-角色,可换为从DB查询
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        String finalPassword = "{bcrypt}" + bCryptPasswordEncoder.encode("123456");

        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(User.withUsername("user").password(finalPassword).authorities("ROLE_USER").build());
        manager.createUser(User.withUsername("vip").password(finalPassword).authorities("ROLE_VIP").build());
        manager.createUser(User.withUsername("admin").password(finalPassword).authorities("ROLE_ADMIN").build());

        return manager;
    }

    @Bean
    PasswordEncoder passwordEncoder() {
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }

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

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

}

  e.对外提供获取用户信息的接口

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

    Logger logger = LoggerFactory.getLogger(UserController.class);

    @RequestMapping(value = "/current", method = RequestMethod.GET)
    public Principal getUser(Principal principal) {
        logger.info(">>>>>>>>>>>>>>>>>>>>>>>>");
        logger.info(principal.toString());
        logger.info(">>>>>>>>>>>>>>>>>>>>>>>>");
        return principal;
    }
}

  f.启动类加上@EnableResourceServer注解开启资源服务

@SpringBootApplication
@EnableResourceServer
@EnableEurekaClient
public class OauthClientApplication {

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

}

3.创建资源服务器

  a.创建SpringBoot工程,依赖选择Eureka Discovery 、Web、Cloud Oauth2 以及 Feign

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth2</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

        .....

    </dependencies>

  b.修改 application.yml 配置

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8081/eureka/
server:
  port: 8083
spring:
  application:
    name: service-client
security:
  oauth2:
    #用户信息url
    resource:
      user-info-uri: http://localhost:8082/users/current
    #客户端信息,与oauth-client的配置一致
    client:
      id: client_1
      client-secret: 123456
      access-token-uri: http://localhost:8082/oauth/token
      grant-type: client_credentials,password
      scope: server

  c.创建 ResourceServerConfiguration 继承 ResourceServerConfigurerAdapter

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

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/order/**").hasAnyRole("ADMIN", "VIP")
                .antMatchers("/product/**").authenticated();
    }

}

  d.创建 OAuth2ClientConfig,添加注解@EnableOAuth2Client开启OAuth2 Client功能

@EnableOAuth2Client
@EnableConfigurationProperties
@Configuration
public class OAuth2ClientConfig {

    @Bean
    @ConfigurationProperties(prefix = "security.oauth2.client")
    public ClientCredentialsResourceDetails clientCredentialsResourceDetails() {
        return new ClientCredentialsResourceDetails();
    }

    @Bean
    public RequestInterceptor oauth2FeignRequestInterceptor() {
        return new OAuth2FeignRequestInterceptor(new DefaultOAuth2ClientContext(), clientCredentialsResourceDetails());
    }

    @Bean
    public OAuth2RestTemplate clientCredentialsRestTemplate() {
        return new OAuth2RestTemplate(clientCredentialsResourceDetails());
    }

}

  e.创建Controller测试

@RestController
public class CommonController {

    Logger logger = LoggerFactory.getLogger(CommonController.class);

    @GetMapping("/product/{id}")
    public String getProduct(@PathVariable String id) {
        return "product id : " + id;
    }

    @GetMapping("/order/{id}")
    public String getOrder(@PathVariable String id) {
        return "order id : " + id;
    }

    @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());

        return oAuth2Authentication;
    }

}

  f.启动类添加 @EnableEurekaClient 注解表示 Eureka 客户端

@SpringBootApplication
@EnableEurekaClient
public class ServiceHiApplication {

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

4.测试:

  a.依次启动 Eureka服务器、Oauth2服务器、资源服务器 (Redis也需要启动)

  b.打开浏览器访问 http://localhost:8082/oauth/token?username=user&password=123456&grant_type=password&scope=select&client_id=client_2&client_secret=123456 获取 access_token

  c.分别不带 token 访问 http://localhost:8083/order/1 以及带 token 访问 http://localhost:8083/order/1?access_token=d3631d4b-f710-468b-aa3f-26d72a23064a

  d.分别不带 token 访问 http://localhost:8083/product/1 以及带 token 访问 http://localhost:8083/product/1?access_token=d3631d4b-f710-468b-aa3f-26d72a23064a

5.参考文档:https://www.jianshu.com/p/3427549a148a

猜你喜欢

转载自www.cnblogs.com/vettel0329/p/11783284.html