欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring Security 多過(guò)濾鏈的使用詳解

 更新時(shí)間:2021年07月15日 08:52:29   作者:huan_1993  
本文主要介紹了Spring Security 多過(guò)濾鏈的使用,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

一、背景

在我們實(shí)際的開(kāi)發(fā)過(guò)程中,有些時(shí)候可能存在這么一些情況,某些api 比如: /api/** 這些是給App端使用的,數(shù)據(jù)的返回都是以JSON的格式返回,且這些API的認(rèn)證方式都是使用的TOKEN進(jìn)行認(rèn)證。而除了 /api/** 這些API之外,都是給網(wǎng)頁(yè)端使用的,需要使用表單認(rèn)證,給前端返回的
都是某個(gè)頁(yè)面。

二、需求

1、給客戶端使用的api

  • 攔截 /api/**所有的請(qǐng)求。
  • /api/**的所有請(qǐng)求都需要ROLE_ADMIN的角色。
  • 從請(qǐng)求頭中獲取 token,只要獲取到token的值,就認(rèn)為認(rèn)證成功,并賦予ROLE_ADMIN到角色。
  • 如果沒(méi)有權(quán)限,則給前端返回JSON對(duì)象 {message:"您無(wú)權(quán)限訪問(wèn)"}
  • 訪問(wèn) /api/userInfo端點(diǎn)
    • 請(qǐng)求頭攜帶 token 可以訪問(wèn)。
    • 請(qǐng)求頭不攜帶token不可以訪問(wèn)。

2、給網(wǎng)站使用的api

  • 攔截 所有的請(qǐng)求,但是不處理/api/**開(kāi)頭的請(qǐng)求。
  • 所有的請(qǐng)求需要ROLE_ADMIN的權(quán)限。
  • 沒(méi)有權(quán)限,需要使用表單登錄。
  • 登錄成功后,訪問(wèn)了無(wú)權(quán)限的請(qǐng)求,直接跳轉(zhuǎn)到百度去。
  • 構(gòu)建2個(gè)內(nèi)建的用戶
    • 用戶一: admin/admin 擁有 ROLE_ADMIN 角色
    • 用戶二:dev/dev 擁有 ROLE_DEV 角色
  • 訪問(wèn) /index 端點(diǎn)
    • admin 用戶訪問(wèn),可以訪問(wèn)。
    • dev 用戶訪問(wèn),不可以訪問(wèn),權(quán)限不夠。

三、實(shí)現(xiàn)方案

方案一:

直接拆成多個(gè)服務(wù),其中 /api/** 的成為一個(gè)服務(wù)。非/api/**的拆成另外一個(gè)服務(wù)。各個(gè)服務(wù)使用自己的配置,互不影響。

方案二

在同一個(gè)服務(wù)中編寫(xiě)。不同的請(qǐng)求使用不同的SecurityFilterChain來(lái)實(shí)現(xiàn)。

經(jīng)過(guò)考慮,此處采用方案二來(lái)實(shí)現(xiàn),因?yàn)榉桨敢缓?jiǎn)單,使用方案二實(shí)現(xiàn),也可以記錄下在同一個(gè)項(xiàng)目中 通過(guò)使用多條過(guò)濾器鏈,因?yàn)椴⒉皇撬械臅r(shí)候,都是可以分成多個(gè)項(xiàng)目的。

擴(kuò)展:

1、Spring Security SecurityFilterChain 的結(jié)構(gòu)

SecurityFilterChain的結(jié)構(gòu)

2、控制 SecurityFilterChain 的執(zhí)行順序

使用 org.springframework.core.annotation.Order 注解。

3、查看是怎樣選擇那個(gè) SecurityFilterChain

查看 org.springframework.web.filter.DelegatingFilterProxy#doFilter方法

四、實(shí)現(xiàn)

1、app 端 Spring Security 的配置

package com.huan.study.security.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.nio.charset.StandardCharsets;

/**
 * 給 app 端用的 Security 配置
 *
 * @author huan.fu 2021/7/13 - 下午9:06
 */
@Configuration
public class AppSecurityConfig {

    /**
     * 處理 給 app(前后端分離) 端使用的過(guò)濾鏈
     * 以 json 的數(shù)據(jù)格式返回給前端
     */
    @Bean
    @Order(1)
    public SecurityFilterChain appSecurityFilterChain(HttpSecurity http) throws Exception {
        // 只處理 /api 開(kāi)頭的請(qǐng)求
        return http.antMatcher("/api/**")
                .authorizeRequests()
                // 所有以 /api 開(kāi)頭的請(qǐng)求都需要 ADMIN 的權(quán)限
                    .antMatchers("/api/**")
                    .hasRole("ADMIN")
                    .and()
                // 捕獲到異常,直接給前端返回 json 串
                .exceptionHandling()
                    .authenticationEntryPoint((request, response, authException) -> {
                        response.setStatus(HttpStatus.UNAUTHORIZED.value());
                        response.setCharacterEncoding(StandardCharsets.UTF_8.name());
                        response.setContentType(MediaType.APPLICATION_JSON.toString());
                        response.getWriter().write("{\"message:\":\"您無(wú)權(quán)訪問(wèn)01\"}");
                    })
                    .accessDeniedHandler((request, response, accessDeniedException) -> {
                        response.setStatus(HttpStatus.UNAUTHORIZED.value());
                        response.setCharacterEncoding(StandardCharsets.UTF_8.name());
                        response.setContentType(MediaType.APPLICATION_JSON.toString());
                        response.getWriter().write("{\"message:\":\"您無(wú)權(quán)訪問(wèn)02\"}");
                    })
                    .and()
                // 用戶認(rèn)證
                .addFilterBefore((request, response, chain) -> {
                    // 此處可以模擬從 token 中解析出用戶名、權(quán)限等
                    String token = ((HttpServletRequest) request).getHeader("token");
                    if (!StringUtils.hasText(token)) {
                        chain.doFilter(request, response);
                        return;
                    }
                    Authentication authentication = new TestingAuthenticationToken(token, null,
                            AuthorityUtils.createAuthorityList("ROLE_ADMIN"));
                    SecurityContextHolder.getContext().setAuthentication(authentication);
                    chain.doFilter(request, response);
                }, UsernamePasswordAuthenticationFilter.class)
                .build();
    }
}

2、網(wǎng)站端 Spring Secuirty 的配置

package com.huan.study.security.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
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.WebSecurityCustomizer;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;

/**
 * 給 網(wǎng)站 應(yīng)用的安全配置
 *
 * @author huan.fu 2021/7/14 - 上午9:09
 */
@Configuration
public class WebSiteSecurityFilterChainConfig {
    /**
     * 處理 給 webSite(非前后端分離) 端使用的過(guò)濾鏈
     * 以 頁(yè)面 的格式返回給前端
     */
    @Bean
    @Order(2)
    public SecurityFilterChain webSiteSecurityFilterChain(HttpSecurity http) throws Exception {

        AuthenticationManagerBuilder authenticationManagerBuilder = http.getSharedObject(AuthenticationManagerBuilder.class);

        // 創(chuàng)建用戶
        authenticationManagerBuilder.inMemoryAuthentication()
                .withUser("admin")
                    .password(new BCryptPasswordEncoder().encode("admin"))
                    .authorities(AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_ADMIN"))
                    .and()
                .withUser("dev")
                    .password(new BCryptPasswordEncoder().encode("dev"))
                    .authorities(AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_DEV"))
                    .and()
                .passwordEncoder(new BCryptPasswordEncoder());

        // 只處理 所有 開(kāi)頭的請(qǐng)求
        return http.antMatcher("/**")
                .authorizeRequests()
                // 所有請(qǐng)求都必須要認(rèn)證才可以訪問(wèn)
                    .anyRequest()
                    .hasRole("ADMIN")
                    .and()
                // 禁用csrf
                .csrf()
                    .disable()
                // 啟用表單登錄
                .formLogin()
                    .permitAll()
                    .and()
                // 捕獲成功認(rèn)證后無(wú)權(quán)限訪問(wèn)異常,直接跳轉(zhuǎn)到 百度
                .exceptionHandling()
                    .accessDeniedHandler((request, response, exception) -> {
                        response.sendRedirect("http://www.baidu.com");
                    })
                    .and()
                .build();
    }

    /**
     * 忽略靜態(tài)資源
     */
    @Bean
    public WebSecurityCustomizer webSecurityCustomizer( ){
        return web -> web.ignoring()
                .antMatchers("/**/js/**")
                .antMatchers("/**/css/**");

    }
}

3、控制器寫(xiě)法

/**
 * 資源控制器
 *
 * @author huan.fu 2021/7/13 - 下午9:33
 */
@Controller
public class ResourceController {

    /**
     * 返回用戶信息
     */
    @GetMapping("/api/userInfo")
    @ResponseBody
    public Authentication showUserInfoApi() {
        return SecurityContextHolder.getContext().getAuthentication();
    }

    @GetMapping("/index")
    public String index(Model model){
        model.addAttribute("username","張三");
        return "index";
    }
}

4、引入jar包

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

五、實(shí)現(xiàn)效果

1、app 有權(quán)限訪問(wèn) api

app 有權(quán)限訪問(wèn) api

2、app 無(wú)權(quán)限訪問(wèn) api

app 無(wú)權(quán)限訪問(wèn) api

3、admin 用戶有權(quán)限訪問(wèn) 網(wǎng)站 api

admin 用戶有權(quán)限訪問(wèn) 網(wǎng)站 api

4、dev 用戶無(wú)權(quán)限訪問(wèn) 網(wǎng)站 api

dev 用戶無(wú)權(quán)限訪問(wèn) 網(wǎng)站 api

訪問(wèn)無(wú)權(quán)限的API直接跳轉(zhuǎn)到 百度 首頁(yè)。

六、完整代碼

https://gitee.com/huan1993/Spring-Security/tree/master/multi-security-filter-chain

到此這篇關(guān)于Spring Security 多過(guò)濾鏈的使用詳解的文章就介紹到這了,更多相關(guān)Spring Security 多過(guò)濾鏈 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • JavaWEB中Servlet的生命周期詳解

    JavaWEB中Servlet的生命周期詳解

    大家好,本篇文章主要講的是JavaWEB中Servlet的生命周期詳解,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下
    2022-01-01
  • 如何使用兩個(gè)棧實(shí)現(xiàn)隊(duì)列Java

    如何使用兩個(gè)棧實(shí)現(xiàn)隊(duì)列Java

    這篇文章主要介紹了如何使用兩個(gè)棧實(shí)現(xiàn)隊(duì)列Java,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-11-11
  • Java基礎(chǔ)第二篇方法與數(shù)據(jù)成員

    Java基礎(chǔ)第二篇方法與數(shù)據(jù)成員

    在上一篇文章中介紹了Java基礎(chǔ) 從HelloWorld到面向?qū)ο?,我們初步了解了?duì)象(object)。對(duì)象中的數(shù)據(jù)成員表示對(duì)象的狀態(tài)。對(duì)象可以執(zhí)行方法,表示特定的動(dòng)作。這篇文章我們進(jìn)一步深入到對(duì)象。了解Java中方法與數(shù)據(jù)成員的一些細(xì)節(jié)。
    2021-09-09
  • Spring純注解開(kāi)發(fā)模式讓開(kāi)發(fā)簡(jiǎn)化更簡(jiǎn)化

    Spring純注解開(kāi)發(fā)模式讓開(kāi)發(fā)簡(jiǎn)化更簡(jiǎn)化

    Spring3.0引入了純注解開(kāi)發(fā)的模式,框架的誕生是為了簡(jiǎn)化開(kāi)發(fā),那注解開(kāi)發(fā)就是簡(jiǎn)化再簡(jiǎn)化。Spring的特性在整合MyBatis方面體現(xiàn)的淋漓盡致哦
    2022-08-08
  • Spring超詳細(xì)講解事務(wù)和事務(wù)傳播機(jī)制

    Spring超詳細(xì)講解事務(wù)和事務(wù)傳播機(jī)制

    Spring事務(wù)的本質(zhì)就是對(duì)數(shù)據(jù)庫(kù)事務(wù)的支持,沒(méi)有數(shù)據(jù)庫(kù)事務(wù),Spring是無(wú)法提供事務(wù)功能的。Spring只提供統(tǒng)一的事務(wù)管理接口,具體實(shí)現(xiàn)都是由數(shù)據(jù)庫(kù)自己實(shí)現(xiàn)的,Spring會(huì)在事務(wù)開(kāi)始時(shí),根據(jù)當(dāng)前設(shè)置的隔離級(jí)別,調(diào)整數(shù)據(jù)庫(kù)的隔離級(jí)別,由此保持一致
    2022-06-06
  • SpringBoot中如何統(tǒng)一接口返回與全局異常處理詳解

    SpringBoot中如何統(tǒng)一接口返回與全局異常處理詳解

    全局異常處理是個(gè)比較重要的功能,一般在項(xiàng)目里都會(huì)用到,這篇文章主要給大家介紹了關(guān)于SpringBoot中如何統(tǒng)一接口返回與全局異常處理的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2021-09-09
  • 輕松學(xué)會(huì)使用JavaMail?API發(fā)送郵件

    輕松學(xué)會(huì)使用JavaMail?API發(fā)送郵件

    想要輕松學(xué)會(huì)使用JavaMail?API發(fā)送郵件嗎?本指南將帶你快速掌握這一技能,讓你能夠輕松發(fā)送電子郵件,無(wú)論是個(gè)人還是工作需求,跟著我們的步驟,很快你就可以在Java應(yīng)用程序中自如地處理郵件通信了!
    2023-12-12
  • springboot 定時(shí)任務(wù)@Scheduled實(shí)現(xiàn)解析

    springboot 定時(shí)任務(wù)@Scheduled實(shí)現(xiàn)解析

    這篇文章主要介紹了springboot 定時(shí)任務(wù)@Scheduled實(shí)現(xiàn)解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-09-09
  • Java程序去調(diào)用并執(zhí)行shell腳本及問(wèn)題總結(jié)(推薦)

    Java程序去調(diào)用并執(zhí)行shell腳本及問(wèn)題總結(jié)(推薦)

    這篇文章主要介紹了Java程序去調(diào)用并執(zhí)行shell腳本及問(wèn)題總結(jié),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-06-06
  • 解決Java原生壓縮組件不支持中文文件名亂碼的問(wèn)題

    解決Java原生壓縮組件不支持中文文件名亂碼的問(wèn)題

    本篇文章主要介紹了解決Java原生壓縮組件不支持中文文件名亂碼的問(wèn)題,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。
    2017-03-03

最新評(píng)論