SpringCloud系列三:SpringSecurity 安全訪問(配置安全驗證、服務消費端處理、無狀態 Session 配置、定義公共安全配置程序類)


聲明:本文來源於MLDN培訓視頻的課堂筆記,寫在這里只是為了方便查閱。

1、概念:SpringSecurity 安全訪問

2、具體內容

所有的 Rest 服務最終都是暴露在公網上的,也就是說如果你的 Rest 服務屬於一些你自己公司的私人業務,這樣的結果會直接 導致你信息的泄漏,所以對於 Rest 訪問,安全性是首要的因素。

2.1、配置安全驗證

如果要想進行安全的驗證處理,那么首先一定要先在服務的提供方上進行處理。

1、 【microcloud-provider-dept-8001】修改 pom.xml 配置文件,追加 SpringSecurity 相關依賴包引入:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

如果你現在配置了安全框架,則在啟動時會出現有如下的一個提示信息:

Using default security password: 75f5d975-0cfc-16e9-b9cc-68fbb0b56465

2、 【microcloud-provider-dept-8001】修改 application.yml 配置文件,進行安全的用戶名配置:

security:
  basic:
    enabled: true # 啟用SpringSecurity的安全配置項
  user:
    name: studyjava  # 認證用戶名
    password: hello # 認證密碼
    role:        # 授權角色
    - USER

隨后在項目之中訪問 Rest 服務接口:http://dept-8001.com:8001/dept/list,此時在訪問的時候會直接詢問用戶要求用戶輸入用戶 名以及密碼。

 

 這個時候有一種更簡化的方法進行內容的輸入:http:/studyjava:hello@dept-8001.com:8001/dept/list;

 2.2、服務消費端處理

 在實際的開發之中,對於 Rest 服務提供者是不可能被用戶直接進行訪問的,於是肯定需要有一個 Rest 客戶端(WEB 端、 SpringBoot)進行調用,可是現在 Rest 提供者的服務上有了認證信息,那么該如何訪問呢?

 public static final String DEPT_GET_URL = "http://studyjava:hello@dept-8001.com:8001/dept/get/";

 如果這個時候在 Rest 客戶端上直接使用用戶名和密碼做加密處理,那么根本就無法進行訪問,此時會出現有 401 的錯誤代碼, 因為認證出現了錯誤。之所以無法訪問,是因為所有的認證的處理操作,應該以頭信息的模式來進行處理。而后要使用Base64進行加密處理后才可以得到一個正確的訪問路徑。

 1、 【microcloud-consumer-80】修改 RestConfig 配置類,在這個配置類上追加有新的 Bean 配置項HttpHeaders 

package cn.study.microcloud.config;

import java.nio.charset.Charset;
import java.util.Base64;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RestConfig {
   @Bean public HttpHeaders getHeaders() { // 要進行一個Http頭信息配置
        HttpHeaders headers = new HttpHeaders(); // 定義一個HTTP的頭信息
        String auth = "studyjava:hello"; // 認證的原始信息
        byte[] encodedAuth = Base64.getEncoder()
                .encode(auth.getBytes(Charset.forName("US-ASCII"))); // 進行一個加密的處理
        // 在進行授權的頭信息內容配置的時候加密的信息一定要與“Basic”之間有一個空格
        String authHeader = "Basic " + new String(encodedAuth);
        headers.set("Authorization", authHeader);
        return headers; }

    @Bean
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
}

 2、 【microcloud-consumer-80】修改 ConsumerDeptController 配置類,在進行 Rest 訪問的時候設置好這個頭部的信息

package cn.study.microcloud.controller;

import java.util.List;

import javax.annotation.Resource;

import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import cn.study.vo.Dept;

@RestController
public class ConsumerDeptController {
    public static final String DEPT_GET_URL = "http://dept-8001.com:8001/dept/get/";
    public static final String DEPT_LIST_URL = "http://dept-8001.com:8001/dept/list/";
    public static final String DEPT_ADD_URL = "http://dept-8001.com:8001/dept/add?dname=";
    @Resource
    private RestTemplate restTemplate;
    @Resource private HttpHeaders headers;
    @RequestMapping(value = "/consumer/dept/get")
    public Object getDept(long id) {
        Dept dept = this.restTemplate
                .exchange(DEPT_GET_URL + id, HttpMethod.GET,
                        new HttpEntity<Object>(this.headers), Dept.class)
                .getBody();
        return dept;
    }
    @SuppressWarnings("unchecked")
    @RequestMapping(value = "/consumer/dept/list")
    public Object listDept() {
        List<Dept> allDepts = this.restTemplate
                .exchange(DEPT_LIST_URL, HttpMethod.GET,
                        new HttpEntity<Object>(this.headers), List.class)
                .getBody();
        return allDepts;
    }
    @RequestMapping(value = "/consumer/dept/add")
    public Object addDept(Dept dept) throws Exception {
        Boolean flag = this.restTemplate.exchange(DEPT_ADD_URL, HttpMethod.POST,
                new HttpEntity<Object>(dept, this.headers), Boolean.class)
                .getBody();
        return flag;
    }
}

 3、無狀態 Session 配置

 通過之前一系列的演示可以發現整個 Rest 項目中的一個問題所在,所有的 Rest 都是基於 HTTP 協議的一種應用,而在這種應 用上,所有的 WEB 容器一般都會提供有一個 Session 的機制,也就是說每一個用戶訪問之后如果該用戶一直連接,則認為該用戶 應該一直被服務器保存狀態,但是微服務有可能同時並發訪問幾十萬人,那么如果所有的 Session 狀態都被維護着就會出現內存泄漏

 1、 【microcloud-provider-dept-8001】現在修改 Rest 程序類,追加一個取得 session id 的方法:

package cn.study.microcloud.rest;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import cn.study.microcloud.service.IDeptService;
import cn.study.vo.Dept;

@RestController
public class DeptRest {
    @Resource
    private IDeptService deptService ;
    @RequestMapping("/dept/sessionId") public Object id(HttpServletRequest request) { return request.getSession().getId() ; }
    
    @RequestMapping(value="/dept/get/{id}",method=RequestMethod.GET)
    public Object get(@PathVariable("id") long id) {
        return this.deptService.get(id) ;
    }
    @RequestMapping(value="/dept/add",method=RequestMethod.POST)
    public Object add(@RequestBody Dept dept) {
        return this.deptService.add(dept) ;
    }
    @RequestMapping(value="/dept/list",method=RequestMethod.GET)
    public Object list() {
        return this.deptService.list() ;
    }
}

 隨后進行提供者的 Rest 連接訪問:http://studyjava:hello@dept-8001.com:8001/dept/sessionId;會發現每訪問一次就會出現不同的session id

 2、 在有一些的 SpringCloud 的配置之中,默認是會保存有 Session 狀態的,而后如果用戶有需要則可以根據“SessionCreationPolicy” 枚舉類進行不同的 session 狀態設置,但是從整體的操作來說,session 最好設置為無狀態。

 · 以下為保持 Session 狀態(服務器內存有可能被占滿):

security:
  sessions: always

 · 以下為無狀態的 Session 設置(服務器不保存 Session 狀態,每一次連接都是一個新的用戶):

security:
  sessions: stateless 

 不管你以后的項目或者支持類中是否有設置無狀態的問題,你最好都進行一下設置,否則你的 Rest 服務將受到嚴重的內存困 擾,最嚴重的問題就是內存溢出。

 4、定義公共安全配置程序類

 在進行 Rest 服務開發的時候,為了保證安全所有的程序里面都需要進行 Spring-Security 安全認證處理,可是之前所進行的認 證處理都是在 application.yml 配置文件完成的,這樣的配置明顯是非常不合乎邏輯的,因為如果此時你要開發的微服務很多,並且 這些微服務都要求使用統一的用戶名和密碼的時候就非常不方便了。所以現在最簡單的做法是進行統一的設置。

 1、 創建一個 microcloud-security 的 Maven 模塊;

 2、 【microcloud-security】修改 pom.xml 配置文件添加spring-boot-starter-security:

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>springloaded</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
    </dependencies>

 3、 【microcloud-security】建立一個統一的安全配置類:

package cn.study.microcloud.config;

import javax.annotation.Resource;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.config.http.SessionCreationPolicy;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Resource
    public void configGlobal(AuthenticationManagerBuilder auth)
            throws Exception {
        auth.inMemoryAuthentication().withUser("studyjava").password("hello")
                .roles("USER").and().withUser("admin").password("hello")
                .roles("USER", "ADMIN");
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 表示所有的訪問都必須進行認證處理后才可以正常進行
        http.httpBasic().and().authorizeRequests().anyRequest()
                .fullyAuthenticated();
        // 所有的Rest服務一定要設置為無狀態,以提升操作性能
        http.sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }
}

 4、 【microcloud-provider-dept-8001】修改 pom.xml 配置文件,引入安全配置模塊:

        <dependency>
            <groupId>cn.study</groupId>
            <artifactId>microcloud-security</artifactId>
        </dependency>

 5、 【microcloud-provider-dept-8001】刪除掉 application.yml 中與安全有關的配置項(以下內容刪除);

security:
 sessions: stateless
 basic:
  enabled: true # 啟用SpringSecurity的安全配置項
 user:
  name: studyjava # 認證用戶名
  password: hello # 認證密碼
  role: # 授權角色
  - USER

 由於現在所寫的安全處理類是在程序啟動類的子包之中,應該可以自動掃描到。

 6、 訪問地址:http://mldnjava:hello@dept-8001.com:8001/dept/sessionId


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM