OAuth2 使用Zuul細粒度權限控制筆記

先置條件(基於我的項目) 假設我現在 有gateway-service(網關)    auth-service(權限認證) game-service(遊戲)  ad-service (廣告)

使用相關版本如下:(版本搭配參考:https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E)

<!--springboot 版本-->
<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.5.RELEASE</version>
</parent>

 <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-cloud.version>Hoxton.SR3</spring-cloud.version>
        <spring-cloud-alibaba.version>2.2.0.RELEASE</spring-cloud-alibaba.version>
</properties>

<dependencyManagement>
        <dependencies>
            <!--整合spring cloud-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--整合spring cloud alibaba-->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
</dependencyManagement>


1.game-service 通過feign調用 ad-service服務 現在要細粒度控制權限 採用OAuth2 來實現 首先4個微服務 都添加如下依賴:

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

2.gateway-service(網關)  game-service(遊戲)  ad-service (廣告) yml 配置文件添加配置

security:
  oauth2:
    client:
      #client-id  client-secret 請根據自己不同的服務 填寫配置信息
      client-id: gateway_client
      client-secret: 123456
    resource:
      jwt:
        #這個是認證服務器地址 即auth-service
        key-uri: http://localhost:8032/oauth/token_key  #訪問路徑參考源碼 org.springframework.security.oauth2.provider.endpoint

3.實現微服務之間權限控制

//在需要控制的方法上添加註解
@PreAuthorize("#oauth2.hasScope('delete')")


//啓動類上添加註解 prePostEnabled即在請求方法之前執行校驗
@EnableGlobalMethodSecurity(prePostEnabled = true)

4.針對具體用戶

//@see org.springframework.security.core.userdetails
//添加訪問方法的控制具體用戶註解 hasRole權限有哪些 是通過UserDetailsService中的loadUserByUsername方法來加載
@PreAuthorize("hasRole('ROLE_ADMIN')")


//啓動類上添加註解 prePostEnabled即在請求方法之前執行校驗
@EnableGlobalMethodSecurity(prePostEnabled = true)

5.如果角色和權限 實時在變化 以上方式就不太合適 假設我現在有一個權限控制系統來獲取用戶擁有的角色或者權限 那麼怎麼在網關上來集成並實現呢

//修改網關配置 指定訪問規則表達式 permissionService.hasPermission(request,authentication)
@Configuration
@EnableResourceServer
public class ZuulSecurityConfig extends ResourceServerConfigurerAdapter  {

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

    }

    /**
     * @param http
     * @throws Exception
     */
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/token/**").permitAll()
             .anyRequest().access("#permissionService.hasPermission(request,authentication)");    //指定訪問規則 authentication當前用戶
    }
}

這樣寫是不會生效的 我們需要自己來實現 PermissionService 

import org.springframework.security.core.Authentication;

import javax.servlet.http.HttpServletRequest;

/**
 * @author Jax
 * @Description 權限控制接口
 * @Date 2020/6/27 13:11
 */
public interface PermissionService {

    boolean hasPermission(HttpServletRequest request, Authentication auth);
}

實現這個方法

import cn.hutool.core.util.RandomUtil;
import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;

/**
 * @author Jax
 * @Description 權限控制實現類
 * @Date 2020/6/27 13:13
 */
@Service
public class PermissionServiceImpl implements PermissionService {
    @Override
    public boolean hasPermission(HttpServletRequest request, Authentication auth) {
        //TODO 需要查詢業務邏輯 來獲取用戶的權限信息 這裏採用 反射方法 打印
        System.err.println(request.getRequestURI());
        System.err.println(ReflectionToStringBuilder.toString(auth));
        return RandomUtil.randomInt() % 2 == 0;
    }
}

然後重寫權限表達式解析方法

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.provider.expression.OAuth2WebSecurityExpressionHandler;
import org.springframework.security.web.FilterInvocation;
import org.springframework.stereotype.Component;

/**
 * @author Jax
 * @Description 權限表達式解析處理器
 * @Date 2020/6/27 13:23
 */
@Component
public class ZuulWebSecurityExpressionHandler extends OAuth2WebSecurityExpressionHandler {
    //注入我們自己的permissionService
    @Autowired
    private PermissionService permissionService;

    /**
     * 創建一個評估的上下文
     * @param authentication
     * @param invocation
     * @return
     */
    @Override
    protected StandardEvaluationContext createEvaluationContextInternal(Authentication authentication, FilterInvocation invocation) {
        StandardEvaluationContext standardEvaluationContext = super.createEvaluationContextInternal(authentication, invocation);
        standardEvaluationContext.setVariable("permissionService",permissionService);
        return standardEvaluationContext;
    }
}

最後一步 在第5步開始的 ZuulSecurityConfig添加配置

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;

/**
 * @Description 網關資源認證配置
 * @Date 2020/6/24 16:43
 * @Author Jax
 */
@Configuration
@EnableResourceServer
public class ZuulSecurityConfig extends ResourceServerConfigurerAdapter  {

    //注入我們自己的權限表達式解析處理器
    @Autowired
    private ZuulWebSecurityExpressionHandler securityExpressionHandler;

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

    /**
     * @param http
     * @throws Exception
     */
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
              .anyRequest().access("#permissionService.hasPermission(request,authentication)");    //指定訪問規則 authentication當前用戶
    }
}

現在所有的權限 都是在網關來控制 可能會出現越權的情況 可以在每一個微服務都去做權限的校驗(即上述方法 不推薦這樣去做),一般細粒度的權限90%以上都是在網關上來控制 微服務之間互相調的時候 可以使用ip的黑白名單來控制訪問的權限 !

此博客紀錄爲自己項目中需要使用的技術棧而學習的筆記~~~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章