千家信息网

如何进行spring cloud gateway oauth整合

发表于:2024-12-12 作者:千家信息网编辑
千家信息网最后更新 2024年12月12日,这篇文章给大家介绍如何进行spring cloud gateway oauth整合,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。spring cloud gateway 细粒度配
千家信息网最后更新 2024年12月12日如何进行spring cloud gateway oauth整合

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


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

  • pom依赖

            org.springframework.boot        spring-boot-starter-security                  org.springframework.security        spring-security-oauth3-resource-server                 org.springframework.security.oauth        spring-security-oauth3                org.springframework.boot        spring-boot-starter-webflux                org.springframework.cloud        spring-cloud-starter-gateway    
  • 简易校验

/** * * 程序名 : AccessFilter 建立日期: 2018-09-09 作者 : someday 模块 : 网关 描述 : oauth校验 备注 : * version20180909001 * 

* 修改历史 序号 日期 修改人 修改原因 */@Componentpublic class AccessFilter implements GlobalFilter, Ordered { // url匹配器 private AntPathMatcher pathMatcher = new AntPathMatcher(); @Resource private RedisTemplate redisTemplate; @Resource private AuthIgnored authIgnored; @Override public int getOrder() { // TODO Auto-generated method stub return -500; } @Override public Mono 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 params = (Map) 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 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 类说明 */@Componentpublic class AuthorizeConfigManager implements ReactiveAuthorizationManager {    @Resource    private SysServiceDao sysServiceDao;    @Resource    private SysClientDao sysClientDao;    private AntPathMatcher antPathMatcher = new AntPathMatcher();    @Override    public Mono check(Mono 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 list = sysServiceDao.listByClientId(Long.valueOf(String.valueOf(map.get("id"))));                    for (Iterator 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整合就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

0