1. 引入依赖

在springcloudgateway的pom.xml文件中加入以下依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-oauth2-resource-server</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-config</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-web</artifactId>
</dependency>
  1. 配置网关

在application.yml中配置网关的路由规则和OAuth2认证信息:

spring:
  cloud:
    gateway:
      routes:
        - id: user-service
          uri: lb://user-service
          predicates:
            - Path=/users/**
          filters:
            - RewritePath=/users/(?<remaining>.*), /$\{remaining}
            - TokenRelay
        - id: product-service
          uri: lb://product-service
          predicates:
            - Path=/products/**
          filters:
            - RewritePath=/products/(?<remaining>.*), /$\{remaining}
            - TokenRelay
        - id: auth-service
          uri: lb://auth-service
          predicates:
            - Path=/oauth/**
          filters:
            - TokenRelay
      security:
        oauth2:
          client:
            clientId: web
            clientSecret: secret
            accessTokenUri: http://localhost:8080/oauth/token
            userAuthorizationUri: http://localhost:8080/oauth/authorize
          resource:
            userInfoUri: http://localhost:8080/user/me

其中,路由规则中的TokenRelay过滤器用于将OAuth2认证信息传递给后端服务。

  1. 配置安全认证

在SecurityConfig中配置安全认证:

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

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

}

其中,/oauth/**请求不需要认证,其他请求需要认证。

  1. 配置资源服务器

在ResourceServerConfig中配置资源服务器:

@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/user/**").authenticated()
                .anyRequest().permitAll();
    }

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.resourceId("resource");
    }

}

其中,/user/**请求需要认证。

  1. 配置认证服务器

在AuthorizationServerConfig中配置认证服务器:

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private BCryptPasswordEncoder passwordEncoder;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private DataSource dataSource;

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                .withClient("web")
                .secret(passwordEncoder.encode("secret"))
                .authorizedGrantTypes("authorization_code", "refresh_token", "password")
                .scopes("read", "write")
                .autoApprove(true)
                .redirectUris("http://localhost:8081/login/oauth2/code/custom");
    }

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

    @Bean
    public TokenStore tokenStore() {
        return new JdbcTokenStore(dataSource);
    }

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

}

其中,配置了一个clientId为web,clientSecret为secret的客户端,并支持授权码、刷新令牌和密码授权模式,授权范围为read和write,重定向URI为http://localhost:8081/login/oauth2/code/custom。

  1. 配置用户服务

在UserServiceImpl中实现用户服务:

@Service
public class UserServiceImpl implements UserDetailsService {

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        if ("admin".equals(username)) {
            return new User(username, "{bcrypt}$2a$10$8t4M4tOcZ1lXZtqnzF0b7Ojg36yTbTJ0l0CJQ80/JEE6Z89FL9ZC", new ArrayList<>());
        }
        return null;
    }

}

其中,密码为123456,经过BCryptPasswordEncoder加密后的值为$2a$10$8t4M4tOcZ1lXZtqnzF0b7Ojg36yTbTJ0l0CJQ80/JEE6Z89FL9ZC。

  1. 测试

启动认证服务器、用户服务、产品服务和网关,并使用浏览器访问http://localhost:8080/oauth/authorize?client_id=web&response_type=code&scope=read&redirect_uri=http://localhost:8081/login/oauth2/code/custom,登录后返回code。

使用curl获取access_token:

curl -X POST \
  http://localhost:8080/oauth/token \
  -H 'Authorization: Basic d2ViOnNlY3JldA==' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'grant_type=authorization_code&code=XTjKtJ&redirect_uri=http://localhost:8081/login/oauth2/code/custom'

使用curl访问受保护资源:

curl -X GET \
  http://localhost:8080/user/me \
  -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiIsImF1ZCI6IndlYiIsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9vYXV0aC90b2tlbiIsImV4cCI6MTY0ODg3MjI1OSwiaWF0IjoxNjQ4ODc5NjU5LCJqdGkiOiI1MjI2MTUxYi03ZjM5LTQxZDAtOWMzZi1jZmQ2ODA0YmQwMTMifQ.B6jSTU6e8u6p47z9XmBn5nBv7r5rWtdiHqd3wJcgsxvF8cjWmIY9l3qz3jSvP8lKJ4yR7Gwrd0x0fjJt4BPZ0sXO-1cZJvzF8jKfTbABMw_WBQxJxKjGgkNGfZ3q3nE7SgGJ8tMfRgJnAUV4m4t4BmG9XZn1zLlLajZCpKc35XYNXXCwGyT1A2QsT8E9ZzY6OjG1d2QkW8B6ykdD1jwU6eKU6W8u9gY5P5o5v7iH1W8xr1qgQHA3q3vFv5W5h5R9DZzg5ZMv5aW1u8ju1Qyq3wCnVa5GTFZY5dNzZ56c6Zj7v2QW6N8gVUJj6wL7JUxWpLlJZgGc1zJdZIomA0z8GyCJL-2FQ1Q'

如果access_token有效,则返回用户信息。如果access_token无效,则返回401错误。

使用springsecurity568和springcloudgateway实现一个基于oauth21的统一认证网关

原文地址: https://www.cveoy.top/t/topic/b1zN 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录