SpringCloud- Gateway+Security+Oauth2

一、auth服务

使用keytool生成RSA证书jwt.jks,复制到resource目录下,在JDK的bin目录下使用命令:

keytool -genkey -alias jwt -keyalg RSA -keystore jwt.jks

1、创建UserServiceImpl类实现Spring Security的UserDetailsService接口,用于加载用户信息;

2、添加认证服务相关配置Oauth2ServerConfig,需要配置加载用户信息的服务UserServiceImpl   及RSA的钥匙对KeyPair

3、如果你想往JWT中添加自定义信息,比如说登录用户的ID,可以自己实现TokenEnhancer接口;

/***
 * JWT内容增强器
 * @author  albert
 */
@Component
public class JwtTokenEnhancer implements TokenEnhancer{
    @Override
    public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
        SecurityUser securityUser = (SecurityUser)authentication.getPrincipal();
        Map<String, Object> info = new HashMap<>(4);

        //把用户ID设置到JWT中
        info.put("id",securityUser.getId());
        ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(info);
        return accessToken;
    }
}

4、由于网关服务需要RSA公钥来验证签名是否合法,所以认证服务需要有个接口把公钥暴露出来

/**
 * 获取RSA公钥接口
 */
@RestController
public class KeyPairController {
    @Autowired
    private KeyPair keyPair;

    @GetMapping("/rsa/publicKey")
    public Map<String, Object> getKey(){
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        RSAKey key = new RSAKey.Builder(publicKey).build();
        return new JWKSet(key).toJSONObject();
    }
}

 5、不要忘了还需要配置Spring Security,允许获取公钥接口的访问;

/***
 * SpringSecurity配置
 * @author albert
 */
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 允许获取公钥接口的访问
        http.authorizeRequests()
                .requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll()
                .antMatchers("/rsa/publicKey").permitAll()
                .anyRequest()
                .authenticated()
                ;
    }


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

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

}

二、gataway服务

       接下来我们就可以搭建网关服务了,它将作为Oauth2的资源服务、客户端服务使用,对访问微服务的请求进行统一的校验认证和鉴权操作。

 在pom.xml中添加相关依赖,主要是Gateway、Oauth2和JWT相关依赖;

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-config</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-oauth2-client</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-oauth2-jose</artifactId>
    </dependency>
    <dependency>
        <groupId>com.nimbusds</groupId>
        <artifactId>nimbus-jose-jwt</artifactId>
        <version>8.16</version>
    </dependency>
</dependencies>

application.yml添加配置,主要是路由规则配置、Oauth2中RSA公钥配置及路由白名单配置;

server:
  port: 8201
spring:
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true #开启从注册中心动态创建路由的功能
          lower-case-service-id: true #使用小写service-id,默认是大写
      routes: #配置路由路径
        - id: ops-demo
          uri: lb://ops-demo
          predicates:
            - Path=/ops-demo/**
  security:
     oauth2:
       resourceserver:
          jwt:
            jwk-set-uri: 'http://localhost:8201/ops-auth/rsa/publicKey' #配置RSA的公钥访问地址
  redis:
     database: 5
     port: 6379
     host: 172.16.3.71
     password: 123456
secure:
  ignore:
    urls: #配置白名单路径
      - "/ops-auth/oauth/token"
      - "/ops-auth/rsa/publicKey"
logging:
  level:
    com.alibaba.nacos.client.naming: warn

 对网关服务进行配置安全配置,由于Gateway使用的是WebFlux,所以需要使用@EnableWebFluxSecurity注解开启;

/**
 * 资源服务器配置
 * Created by fwone on 2020/6/19.
 * @author albert
 */
@AllArgsConstructor
@Configuration
@EnableWebFluxSecurity
public class ResourceServerConfig {
    // 自定义的认证管理器
    private final AuthorizationManager authorizationManager;
    // 自定义白名单配置
    private final IgnoreUrlsConfig ignoreUrlsConfig;
    // 自定义未授权的处理器
    private final RestfulAccessDeniedHandler restfulAccessDeniedHandler;
    // 自定义未认证的处理器
    private final RestAuthenticationEntryPoint restAuthenticationEntryPoint;
    // 白名单路径,直接移除JWT请求头
    private final IgnoreUrlsRemoveJwtFilter ignoreUrlsRemoveJwtFilter;

    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
        http.oauth2ResourceServer().jwt()
                .jwtAuthenticationConverter(jwtAuthenticationConverter());
        //自定义处理JWT请求头过期或签名错误的结果
        http.oauth2ResourceServer().authenticationEntryPoint(restAuthenticationEntryPoint);
        //对白名单路径,直接移除JWT请求头
        http.addFilterBefore(ignoreUrlsRemoveJwtFilter, SecurityWebFiltersOrder.AUTHENTICATION);
        http.authorizeExchange()
                //预检请求都放行
                .pathMatchers(HttpMethod.OPTIONS).permitAll()
                //白名单配置
                .pathMatchers(ArrayUtil.toArray(ignoreUrlsConfig.getUrls(),String.class)).permitAll()
                //鉴权管理器配置
                .anyExchange().access(authorizationManager)
                .and().exceptionHandling()
                //处理未授权
                .accessDeniedHandler(restfulAccessDeniedHandler)
                //处理未认证
                .authenticationEntryPoint(restAuthenticationEntryPoint)
                .and().csrf().disable();
        return http.build();
    }

    @Bean
    public Converter<Jwt, ? extends Mono<? extends AbstractAuthenticationToken>> jwtAuthenticationConverter() {
        JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
        jwtGrantedAuthoritiesConverter.setAuthorityPrefix(AuthConstant.AUTHORITY_PREFIX);
        jwtGrantedAuthoritiesConverter.setAuthoritiesClaimName(AuthConstant.AUTHORITY_CLAIM_NAME);
        JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
        jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(jwtGrantedAuthoritiesConverter);
        return new ReactiveJwtAuthenticationConverterAdapter(jwtAuthenticationConverter);
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值