1. 程式人生 > >自定義feign配置與服務呼叫的安全驗證

自定義feign配置與服務呼叫的安全驗證

feign的使用,可以簡化服務之間的呼叫,讓服務之間呼叫更加優雅,本文從feign自定義配置和建立feign完成服務之間複雜許可權驗證,來進一步理解和定製feign。

本文示例參考了《Spring Cloud與Docker微服務架構實踐》

自定義配置

  • 建立Feign的配置類
@Configuration
public class FeignConfiguration{
     @Bean
     public Contract feignContract(){
         return new feign.Contract.Default();
    }

    @Bean
public BasicAuthRequestInterceptor basicAuthRequestInterceptor(){ return new BasicAuthRequestInterceptor("user","password"); } }

說明:第一個@Bean配置是在FeignClient中的介面中使用Feign自帶的註解; 第二個@Bean配置是在請求介面中要進行基於Http Basic的認證後才能呼叫。

  • FeignClient介面引用配置
@FeignClient(name="hello", configuration=FeignConfiguration.class)
public
interface HelloService{ @RequestLine("GET /message") HelloMessage hello(); }

需要注意的是: FeignConfiguration類不能包含在主應用程式上下文的@ComponentScan中,否則該配置會被所有的@FeignClient共享。

Ribbon的自定義配置中也需要注意這個問題。

服務呼叫的複雜許可權認證

上面演示了服務之間可以通過自定義配置完成基於Http Basic的認證,但是不能滿足根據不同的角色不同的使用者執行不同的操作,即服務之間的呼叫有更復雜的許可權要求,就不能滿足要求了,這時候要針對feign做進一步的改進。

    <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
  • 關鍵許可權配置(服務提供者)
package com.example.helloauth.configuration;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Collection;

/**
 * @author billjiang [email protected]
 * @create 17-8-26
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception{
        http.authorizeRequests().anyRequest().authenticated().and().httpBasic();
    }


    @Bean
    public PasswordEncoder passwordEncoder(){
        return NoOpPasswordEncoder.getInstance();
    }

    @Autowired
    private CustomUserDetailService userDetailService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception{
        auth.userDetailsService(this.userDetailService).passwordEncoder(this.passwordEncoder());
    }

    @Component
    class CustomUserDetailService implements UserDetailsService{
        @Override
        public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException{
            if("user".equals(username)){
                return new SecurityUser("user","123456","user-role");
            }else if("admin".equals(username)){
                return new SecurityUser("admin","123456","admin-role");
            }else{
                return null;
            }
        }
    }

    class SecurityUser implements UserDetails{
        private static final long serialVersionUID=1L;

        public SecurityUser(String username,String password,String role){
            super();
            this.username=username;
            this.password=password;
            this.role=role;
        }

        public SecurityUser(){

        }

        @Override
        public Collection<? extends GrantedAuthority> getAuthorities() {
            Collection<GrantedAuthority> authorities=new ArrayList<>();
            SimpleGrantedAuthority authority=new SimpleGrantedAuthority(this.role);
            authorities.add(authority);
            return authorities;
        }


        private Long id;
        private String username;
        private String password;
        private String role;

        public Long getId() {
            return id;
        }

        public void setId(Long id) {
            this.id = id;
        }

        @Override
        public String getUsername() {
            return username;
        }

        @Override
        public boolean isAccountNonExpired() {
            return true;
        }

        @Override
        public boolean isAccountNonLocked() {
            return true;
        }

        @Override
        public boolean isCredentialsNonExpired() {
            return true;
        }

        @Override
        public boolean isEnabled() {
            return true;
        }

        public void setUsername(String username) {
            this.username = username;
        }

        @Override
        public String getPassword() {
            return password;
        }

        public void setPassword(String password) {
            this.password = password;
        }

        public String getRole() {
            return role;
        }

        public void setRole(String role) {
            this.role = role;
        }
    }

}

啟動專案hello-auth後,可以見到頁面需要輸入使用者名稱和密碼才能訪問。
許可權認證.png

  • 服務消費者hello-auth-feign修改
    1)去掉啟動類上的@EnableFeignClients註解
    2)去掉介面的@FeignClient的註解
package com.example.helloauthconsumerfeign.service;

import com.example.helloauthconsumerfeign.model.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

/**
 * @author billjiang [email protected]
 * @create 17-8-23
 */
//@FeignClient(value="hello-auth")
public interface HelloAuthService {

    @GetMapping("/{id}")
    User findById(@PathVariable("id") Long id);


}

3)編寫Controller類如下

package com.example.helloauthconsumerfeign.controller;

import com.example.helloauthconsumerfeign.model.User;
import com.example.helloauthconsumerfeign.service.HelloAuthService;
import feign.Client;
import feign.Contract;
import feign.Feign;
import feign.auth.BasicAuthRequestInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import feign.codec.Decoder;
import feign.codec.Encoder;
import org.springframework.cloud.netflix.feign.FeignClientsConfiguration;
import org.springframework.context.annotation.Import;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;


/**
 * @author billjiang [email protected]
 * @create 17-8-26
 */
@Import(FeignClientsConfiguration.class)
@RestController
public class HelloAuthFeignController {
    private HelloAuthService userAuthService;

    private HelloAuthService adminAuthService;

    @Autowired
    public HelloAuthFeignController(Decoder decoder, Encoder encoder, Client client, Contract contract){
        this.userAuthService= Feign.builder().client(client).encoder(encoder).decoder(decoder).contract(contract)
                .requestInterceptor(new BasicAuthRequestInterceptor("user","123456"))
                .target(HelloAuthService.class,"http://hello-auth/");

        this.adminAuthService= Feign.builder().client(client).encoder(encoder).decoder(decoder).contract(contract)
                .requestInterceptor(new BasicAuthRequestInterceptor("admin","123456"))
                .target(HelloAuthService.class,"http://hello-auth/");
    }

    @GetMapping("/user/{id}")
    public User findByIdUser(@PathVariable Long id){
        return this.userAuthService.findById(id);
    }


    @GetMapping("/admin/{id}")
    public User findByIdAdmin(@PathVariable Long id){
        return this.adminAuthService.findById(id);
    }


}
  • 消費者呼叫
    在瀏覽器器分別輸入http://localhost:8031/admin/1http://localhost:8031/user/2則可以完成服務之間授權的呼叫。

在實際業務中會根據不同的角色,執行不同的業務操作,基於以上示例可以在服務之間完成複雜的服務鑑權。

相關推薦

定義feign配置服務呼叫安全驗證

feign的使用,可以簡化服務之間的呼叫,讓服務之間呼叫更加優雅,本文從feign自定義配置和建立feign完成服務之間複雜許可權驗證,來進一步理解和定製feign。 本文示例參考了《Spring Cloud與Docker微服務架構實踐》 自定義配置

spring security起步三:定義登入配置form-login屬性詳解

在上一篇部落格spring security起步二:自定義登入頁中我們實現瞭如何自定義登入頁,但是還存在很多問題: 1.spring security如何對登入請求進行攔截 2.登入成功後如何跳轉 3.登入失敗後如何跳轉 form-login屬性詳解

Springboot專案Netty做服務端並定義Gson配置類解析資料包

簡述 Springboot專案中使用 Netty 作為服務端,接收並處理其他平臺傳送的 Json資料包,處理拆包、粘包及資料包中時間型別是 long 型別需轉成 ***Date***的情況。 專案流程 啟動專案,開啟Netty服務埠11111 載入

elasticsearch 深入 —— 分析器執行順序Mapping定義分析器配置

預設分析器 雖然我們可以在欄位層級指定分析器, 但是如果該層級沒有指定任何的分析器,那麼我們如何能確定這個欄位使用的是哪個分析器呢? 分析器可以從三個層面進行定義:按欄位(per-field)、按索引(per-index)或全域性預設(global default)。El

Feign定義程式設計配置

 介紹 在Spring Cloud中,Feign的預設配置類是FeignClientsConfiguration,該類定義了Feigh預設使用的編碼器、解碼器、所使用的契約等。Spring Cloud允許通過註解@FeignClient的configuration屬性自定義Feign的配置,自定義

Android定義開發SDK呼叫

介紹以.jar/.aar包形式製作自己的SDK,並實現呼叫的過程。將使用OpenCV實現圖片灰度化的方式打包為.jar/.aar包,並實現呼叫,OpenCV使用JNI實現本地方法呼叫。建立一個module用於製作SDK,OpenCV環境搭建和程式碼編寫部分參考一下部落格:部落

JavaScript中定義類寫法呼叫例子

最快入門 類的寫法如下: IntroducerService = function() {     //自身的指標     var me = this;     //公有變數     me.test = "myTest";         // 公有方法     me

jira安裝配置服務腳本

jira安裝部署 jira服務腳本 jira授權一、安裝說明系統:CentOS 6.7 x64 export LANG="zh_CN.UTF-8" # 否則中文無法顯示,還是英文安裝java 1.7.x版本jdk安裝mysql 5.1及以上版本二、數據庫配置創建mysql:>>crea

springCloud(8):Ribbon實現客戶端側負載均衡-定義Ribbon配置

spring cloud ribbon 自定義ribbon配置 一、簡介很多場景下,可能根據需要自定義的Ribbon的配置,例如修改Ribbon的負載均衡規則等。Spring cloud Camden允許使用Java代碼或屬性自定義Ribbon的配置。二、使用Java代碼自定義Ribbon配置在S

定義倉庫配置

layout nap pom.xml pan false pom color 倉庫配置 span 在項目的pom.xml文件中添加repository進行配置,其中id與name自定義,在project標簽中添加如下: <repositories> &

定義View分類流程

ces ted function ram 註意 measure fin 利用 href 自定義View分類與流程(進階篇)## 轉載出處: http://www.gcssloop.com/customview/CustomViewProcess/ 自定義View繪制流程

Unity3D定義資源配置文件

想要 說明 設計 子彈 數值 我們 ret 似的 復制 http://blog.csdn.net/candycat1992/article/details/52181814 寫在前面 我竟然最近兩天才知道Unity中ScriptableObject的存在…… 看了下Sc

SpringCloud系列五:Ribbon 負載均衡(Ribbon 基本使用、Ribbon 負載均衡、定義 Ribbon 配置、禁用 Eureka 實現 Ribbon 調用)

control context .mm 別名 void 用戶 size ali ram 1、概念:Ribbon 負載均衡 2、具體內容 現在所有的服務已經通過了 Eureka 進行了註冊,那麽使用 Eureka 註冊的目的是希望所有的服務都統一歸屬到 Eureka 之中進

Django中創建定義標簽過慮器

IT choices filters AS value ret urn gist doctype 1.首先在app中創建templatetags目錄(註意必須使用該名字,否則系統找不到自定義的標簽),然後創建python文件common_extrgs.py. common_

springSecurity定義認證配置

pojo property ood 目錄 spring註解 web tex poj uri 上一篇講了springSecurity的簡單入門的小demo,認證用戶是在xml中寫死的。今天來說一下自定義認證,讀取數據庫來實現認證。當然,也是非常簡單的,因為僅僅是讀取數據庫,權

配置sshd服務安全密鑰驗證方式

拷貝 term mage nag rest log ces sha 文件 sshd服務有兩種登陸驗證方式:口令驗證——用賬戶和密碼來驗證登陸;密鑰驗證——分為公鑰和私鑰,客戶端通過私鑰連接服務器,服務器通過公鑰來匹配客戶端的私鑰,匹配成功則允許登陸。實驗環境:服務器:192

SpringBoot中讀取定義properties配置文件

bsp clas manage trace etl sstream factory 地址 app 配置文件放在src/main/resources目錄下 java代碼: /** * 系統配置文件 */ public class GlobalProperties {

定義vim配置文件vimrc,用於c/c++編程

which pfile tst nco 檢測 str 字體 normal ada   vim作為Linux下廣受贊譽的代碼編輯器,其獨特的純命令行操作模式可以很大程度上方便編程工作,通過自定義vim配置文件可以實現對vim功能的個性化設置。   vim配置文件一般有兩份,屬

Senparc.Weixin微信開發(3) 定義菜單獲取用戶組

開發 分享圖片 獲取 local lock 自定義 oba summary setting 自定義菜單 代碼參考:http://www.cnblogs.com/szw/p/3750517.html 還可以使用他們官網的自定義:https://neuchar.senparc.

定義xml配置檔案讀取更新

說明:webconfig的檔案中的值的更新會引起網站重啟,網站重啟記憶體揮手,session等資訊會丟失,所以下面這些場景我們需要自定義配置檔案。          1,網站執行中,我們需要更新配置檔案來關閉某些功能,不能造成使用者cookie等