如何进行spring cloud gateway oauth整合

这篇文章给大家介绍如何进行spring cloud gateway oauth整合,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

如何进行spring cloud gateway oauth整合

spring cloud gateway 细粒度配置 spring cloud oauth前后分离项目

如何进行spring cloud gateway oauth整合

  • pom依赖

    <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency> 
    
         <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-oauth3-resource-server</artifactId>
        </dependency> 
    
        <dependency>
            <groupId>org.springframework.security.oauth</groupId>
            <artifactId>spring-security-oauth3</artifactId>
        </dependency>
        <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>
  • 简易校验

/**
 * * 程序名 : AccessFilter 建立日期: 2018-09-09 作者 : someday 模块 : 网关 描述 : oauth校验 备注 :
 * version20180909001
 * <p>
 * 修改历史 序号 日期 修改人 修改原因
 */
@Component
public class AccessFilter implements GlobalFilter, Ordered {

    // url匹配器
    private AntPathMatcher pathMatcher = new AntPathMatcher();

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Resource
    private AuthIgnored authIgnored;

    @Override
    public int getOrder() {
        // TODO Auto-generated method stub
        return -500;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // TODO Auto-generated method stub

        String accessToken = TokenUtil.extractToken(exchange.getRequest());

        // 默认
        boolean flag = false;

        for (String ignored : authIgnored.getIgnored()) {

            if (pathMatcher.match(ignored, exchange.getRequest().getPath().value())) {
                flag = true; // 白名单
            }

        }

        if (flag) {
            return chain.filter(exchange);
        } else {

            Map<String, Object> params = (Map<String, Object>) redisTemplate.opsForValue().get(UaaConstant.TOKEN+":" + accessToken);

            if (params != null) {
                return chain.filter(exchange);
            } else {
                exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);

                ServerHttpResponse response = exchange.getResponse();
                JSONObject message = new JSONObject();
                message.put("resp_code", 401);
                message.put("resp_msg", "未认证通过!");
                byte[] bits = message.toJSONString().getBytes(StandardCharsets.UTF_8);
                DataBuffer buffer = response.bufferFactory().wrap(bits);
                response.setStatusCode(HttpStatus.UNAUTHORIZED);
                // 指定编码,否则在浏览器中会中文乱码
                response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
                return response.writeWith(Mono.just(buffer));
            }

        }

    }

}
package com.open.capacity.client.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.autoconfigure.security.reactive.EndpointRequest;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.security.authentication.ReactiveAuthenticationManager;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.config.web.server.SecurityWebFiltersOrder;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.oauth3.common.OAuth3AccessToken;
import org.springframework.security.oauth3.provider.token.TokenStore;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.server.authentication.AuthenticationWebFilter;
import org.springframework.web.server.WebFilter;

import com.open.capacity.client.handler.ResAccessDeniedHandler;
import com.open.capacity.client.handler.ResAuthenticationEntryPoint;
import com.open.capacity.client.handler.ResAuthenticationFailureHandler;
import com.open.capacity.client.handler.ResAuthenticationSuccessHandler;
import com.open.capacity.client.token.AuthorizeConfigManager;
import com.open.capacity.client.token.TokenAuthenticationConverter;
import com.open.capacity.client.token.TokenAuthenticationManager;
import com.open.capacity.common.auth.props.PermitUrlProperties;

/**
 * 资源服务器UAAClientAutoConfig
 */
@Configuration
@EnableConfigurationProperties(PermitUrlProperties.class)
public class UAAClientAutoConfig {
    @Autowired
    private PermitUrlProperties permitUrlProperties;

    @Autowired
    private TokenStore tokenStore;

    @Autowired
    private AuthorizeConfigManager authorizeConfigManager ;

//    @Resource(name="delegatingAuthorizationManager")
//    private DelegatingReactiveAuthorizationManager delegatingAuthorizationManager;

    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
        //认证处理器
        ReactiveAuthenticationManager tokenAuthenticationManager = new TokenAuthenticationManager(tokenStore);
        ResAuthenticationEntryPoint resAuthenticationEntryPoint = new ResAuthenticationEntryPoint();

        ResAccessDeniedHandler resAccessDeniedHandler = new ResAccessDeniedHandler() ;

        //构建Bearer Token
        //请求参数强制加上 Authorization BEARER token
        http.addFilterAt((WebFilter) (exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest();
            if(request.getQueryParams().getFirst("access_token")!=null) {
                exchange.getRequest().mutate().headers(httpHeaders ->
                        httpHeaders.add(
                            "Authorization",
                            OAuth3AccessToken.BEARER_TYPE+" "+request.getQueryParams().getFirst("access_token"))
                );
            }
            return chain.filter(exchange);
        }, SecurityWebFiltersOrder.FIRST);

        //身份认证
        AuthenticationWebFilter authenticationWebFilter = new AuthenticationWebFilter(tokenAuthenticationManager);
        authenticationWebFilter.setAuthenticationFailureHandler(new ResAuthenticationFailureHandler()); //登陆验证失败
        authenticationWebFilter.setAuthenticationSuccessHandler(new ResAuthenticationSuccessHandler()); //认证成功
        //token转换器
        TokenAuthenticationConverter tokenAuthenticationConverter = new TokenAuthenticationConverter();
        tokenAuthenticationConverter.setAllowUriQueryParameter(true);
        authenticationWebFilter.setServerAuthenticationConverter(tokenAuthenticationConverter);

        http.addFilterAt(authenticationWebFilter, SecurityWebFiltersOrder.AUTHENTICATION);

        //访问授权
//        AuthorizationWebFilter authorizationWebFilter=new AuthorizationWebFilter(delegatingAuthorizationManager);
//        http.addFilterAt(authorizationWebFilter, SecurityWebFiltersOrder.FORM_LOGIN);

        ServerHttpSecurity.AuthorizeExchangeSpec authorizeExchange = http.authorizeExchange();

        authorizeExchange.matchers(EndpointRequest.toAnyEndpoint()).permitAll(); //无需进行权限过滤的请求路径
        authorizeExchange.pathMatchers(permitUrlProperties.getIgnored()).permitAll() ;//无需进行权限过滤的请求路径

        authorizeExchange
                .pathMatchers(HttpMethod.OPTIONS).permitAll()    //option 请求默认放行
//                .anyExchange().access(authorizeConfigManager)  // 应用api权限控制
                 .anyExchange().authenticated()                  //token 有效性控制
                .and()
                    .exceptionHandling()
                        .accessDeniedHandler(resAccessDeniedHandler)
                        .authenticationEntryPoint(resAuthenticationEntryPoint)
                .and()
                    .headers()
                        .frameOptions()
                        .disable()
                .and()
                    .httpBasic().disable()
                    .csrf().disable();
        return http.build();
    }
}
  • token有效期检测

package com.open.capacity.client.token;

import org.springframework.http.HttpStatus;

/*
 * Copyright 2002-2018 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import org.springframework.security.authentication.ReactiveAuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth3.common.OAuth3AccessToken;
import org.springframework.security.oauth3.common.exceptions.InvalidTokenException;
import org.springframework.security.oauth3.core.OAuth3AuthenticationException;
import org.springframework.security.oauth3.core.OAuth3Error;
import org.springframework.security.oauth3.provider.OAuth3Authentication;
import org.springframework.security.oauth3.provider.token.TokenStore;
import org.springframework.security.oauth3.server.resource.BearerTokenAuthenticationToken;
import org.springframework.security.oauth3.server.resource.BearerTokenError;
import org.springframework.security.oauth3.server.resource.BearerTokenErrorCodes;

import reactor.core.publisher.Mono;

/**
 * A {@link ReactiveAuthenticationManager} for Jwt tokens.
 *
 * @author Rob Winch
 * @since 5.1
 */
public final class TokenAuthenticationManager implements ReactiveAuthenticationManager {
    private TokenStore tokenStore;

    public TokenAuthenticationManager(TokenStore tokenStore) {
        this.tokenStore = tokenStore;
    }

    @Override
    public Mono<Authentication> authenticate(Authentication authentication) {
        return Mono.justOrEmpty(authentication)
                .filter(a -> a instanceof BearerTokenAuthenticationToken)
                .cast(BearerTokenAuthenticationToken.class)
                .map(BearerTokenAuthenticationToken::getToken)
                .flatMap((accessTokenValue -> {
                    OAuth3AccessToken accessToken = tokenStore.readAccessToken(accessTokenValue);
                    if (accessToken == null) {
                        OAuth3Error error = new BearerTokenError(
                                BearerTokenErrorCodes.INVALID_TOKEN,
                                HttpStatus.UNAUTHORIZED,
                                "Invalid access token: " + accessTokenValue,
                                "https://tools.ietf.org/html/rfc6750#section-3.1");
                        return Mono.error(new OAuth3AuthenticationException(error,"Invalid access token: " + accessTokenValue));
                    } else if (accessToken.isExpired()) {
                        tokenStore.removeAccessToken(accessToken);
                        OAuth3Error error = new BearerTokenError(
                                BearerTokenErrorCodes.INVALID_TOKEN,
                                HttpStatus.UNAUTHORIZED,
                                "Access token expired: " + accessTokenValue,
                                "https://tools.ietf.org/html/rfc6750#section-3.1");

                        return  Mono.error(new OAuth3AuthenticationException(error,"Access token expired: " + accessTokenValue));
                    }

                    OAuth3Authentication result = tokenStore.readAuthentication(accessToken);
                    if (result == null) {
                        return Mono.error(new InvalidTokenException("Invalid access token: " + accessTokenValue));
                    }
                    return Mono.just(result);
                }))
                .cast(Authentication.class);
    }
}
  • 应用可访问API列表控制

package com.open.capacity.client.token;

import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.ReactiveAuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth3.provider.OAuth3Authentication;
import org.springframework.security.web.server.authorization.AuthorizationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;

import com.open.capacity.client.dao.SysClientDao;
import com.open.capacity.client.dao.SysServiceDao;

import reactor.core.publisher.Mono;

/**
 * @author 作者 owen E-mail: 624191343@qq.com
 * @version 创建时间:2018年2月1日 下午9:47:00 类说明
 */
@Component
public class AuthorizeConfigManager implements ReactiveAuthorizationManager<AuthorizationContext> {

    @Resource
    private SysServiceDao sysServiceDao;

    @Resource
    private SysClientDao sysClientDao;

    private AntPathMatcher antPathMatcher = new AntPathMatcher();

    @Override
    public Mono<AuthorizationDecision> check(Mono<Authentication> authentication,
            AuthorizationContext authorizationContext) {
        return authentication.map(auth -> {

            // TODO 目前都是true
            boolean hasPermission = false;

            ServerWebExchange exchange = authorizationContext.getExchange();
            ServerHttpRequest request = exchange.getRequest();

            if (auth instanceof OAuth3Authentication) {

                OAuth3Authentication athentication = (OAuth3Authentication) auth;

                String clientId = athentication.getOAuth3Request().getClientId();

                Map map = sysClientDao.getClient(clientId);

                if (map == null) {
                    return new AuthorizationDecision(false);
                } else {
                    List<Map> list = sysServiceDao.listByClientId(Long.valueOf(String.valueOf(map.get("id"))));

                    for (Iterator<Map> it = list.iterator(); it.hasNext();) {
                        Map temp = it.next();

                        if (antPathMatcher.match(String.valueOf(temp.get("path")), request.getURI().getPath())) {
                            return new AuthorizationDecision(true);
                        }
                    }
                    return new AuthorizationDecision(false);
                }

            }

            // boolean isPermission = super.hasPermission(auth,
            // request.getMethodValue(), request.getURI().getPath());

            return new AuthorizationDecision(hasPermission);
        }).defaultIfEmpty(new AuthorizationDecision(false));
    }

}

关于如何进行spring cloud gateway oauth整合就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

原创文章,作者:奋斗,如若转载,请注明出处:https://blog.ytso.com/tech/dev/204601.html

(0)
上一篇 2021年11月29日 03:15
下一篇 2021年11月29日 03:15

相关推荐

发表回复

登录后才能评论