主頁 >  其他 > SpringBoot+SpringSecurity+JWT實作認證和授權

SpringBoot+SpringSecurity+JWT實作認證和授權

2021-01-19 11:11:12 其他

一、背景:

在 B/S 系統中,登錄功基本都是依靠 Cookie 來實作的,用戶登錄成功之后主要需要客戶端和服務端完成以下兩項作業:

(1)服務端將登錄狀態記錄到 Session 中,或者簽發Token;

(2)客戶端利用Cookie保存于服務端對應的 Session ID 或 Token,之后每次請求都會帶上Cookie資訊(包含Session ID或者Token),當服務端收到請求后,通過驗證 Cookie 中的資訊來判斷用戶是否登錄 ,

單點登錄: 單點登錄(Single Sign On, SSO)是指在同一帳號平臺下的多個應用系統中,用戶只需登錄一次,即可訪問所有相互信任的應用系統,單點登錄的本質就是在多個應用系統中共享登錄狀態, SSO是目前比較流行的企業業務整合的解決方案之一,

如果用戶的登錄狀態是記錄在 Session 中的,要實作共享登錄狀態,就要先共享 Session,比如可以將 Session 序列化到 Redis 中,讓多個應用系統共享同一個 Redis,直接讀取 Redis 來獲取 Session,當然僅此是不夠的,因為不同的應用系統有著不同的域名,盡管 Session 共享了,但是由于 Session ID 是往往保存在瀏覽器 Cookie 中的,因此存在作用域的限制,無法跨域名傳遞,也就是說當用戶在 app1.com 中登錄后,Session ID 僅在瀏覽器訪問 app1.com 時才會自動在請求頭中攜帶,而當瀏覽器訪問 app2.com 時,Session ID 是不會被帶過去的,實作單點登錄的關鍵在于,如何讓 Session ID(或 Token)在多個域中共享,

目前而言,主要有以下3種方式:

(1)父域 Cookie:例如:baike.baidu.com、wenku.baidu.com、zhida.baidu.com可以將認證的cookie放入baidu.com這個父級域名中,從而實作登錄資訊的共享,此種實作方式比較簡單,但不支持跨主域名,

(2)認證中心:我們可以部署一個認證中心,認證中心就是一個專門負責處理登錄請求的獨立的 Web 服務,用戶統一在認證中心進行登錄,登錄成功后,認證中心記錄用戶的登錄狀態,并將 Token 寫入 Cookie,(注意這個 Cookie 是認證中心的,應用系統是訪問不到的,)

應用系統檢查當前請求有沒有 Token,如果沒有,說明用戶在當前系統中尚未登錄,那么就將頁面跳轉至認證中心,由于這個操作會將認證中心的 Cookie 自動帶過去,因此,認證中心能夠根據 Cookie 知道用戶是否已經登錄過了,如果認證中心發現用戶尚未登錄,則回傳登錄頁面,等待用戶登錄,如果發現用戶已經登錄過了,就不會讓用戶再次登錄了,而是會跳轉回目標 URL ,并在跳轉前生成一個 Token,拼接在目標 URL 的后面,回傳給目標應用系統,

應用系統拿到 Token 之后,還需要向認證中心確認下 Token 的合法性,防止用戶偽造,確認無誤后,應用系統記錄用戶的登錄狀態,并將 Token 寫入 Cookie,然后給本次訪問放行,(注意這個 Cookie 是當前應用系統的,其他應用系統是訪問不到的,)當用戶再次訪問當前應用系統時,就會自動帶上這個 Token,應用系統驗證 Token 發現用戶已登錄,于是就不會有認證中心什么事了,

目前被廣泛使用的方案主要是Apereo CAS ,Apereo CAS 是一個企業級單點登錄系統,其中 CAS 的意思是”Central Authentication Service“,它最初是耶魯大學實驗室的專案,后來轉讓給了 JASIG 組織,專案更名為 JASIG CAS,后來該組織并入了 Apereo 基金會,專案也隨之更名為 Apereo CAS,

(3)LocalStorage 跨域:在前后端分離的情況下,完全可以不使用 Cookie,我們可以選擇將 Session ID (或 Token )保存到瀏覽器的 LocalStorage 中,讓前端在每次向后端發送請求時,主動將 LocalStorage 的資料傳遞給服務端,這些都是由前端來控制的,后端需要做的僅僅是在用戶登錄成功后,將 Session ID (或 Token )放在回應體中傳遞給前端,在這樣的場景下,單點登錄完全可以在前端實作,前端拿到 Session ID (或 Token )后,除了將它寫入自己的 LocalStorage 中之外,還可以通過特殊手段將它寫入多個其他域下的 LocalStorage 中,

二、JWT介紹

JWT概念說明

從分布式認證流程中,我們不難發現,這中間起最關鍵作用的就是token,token的安全與否,直接關系到系統的健壯性,這里我們選擇使用JWT來實作token的生成和校驗,JWT,全稱JSON Web Token,官網地址https://jwt.io,是一款出色的分布式身份校驗方案,可以生成token,也可以決議檢驗token,

JWT生成的token由三部分組成:

該物件為一個很長的字串,字符之間通過"."分隔符分為三個子串, 每一個子串表示了一個功能塊,總共有以下三個部分:JWT 頭、有效載荷和簽名,

頭部JWT 頭部分是一個描述 JWT 元資料的 JSON 物件,主要設定一些規范資訊,簽名部分的編碼格式就在頭部中宣告,

載荷:token中存放有效資訊的部分,是 JWT 的主體內容部分,是一個 JSON 物件,包含需要傳遞的資料,比如用戶名,用戶角色,過期時間等,但是不要放密碼,會泄露!

指定七個默認欄位供選擇,
iss:發行人
exp:到期時間
sub:主題
aud:用戶
nbf:在此之前不可用
iat:發布時間
jti:JWT ID 用于標識該 JWT
除以上默認欄位外,我們還可以自定義私有欄位,如下例:
{
"sub": "11111",
"name": "Atom",
"admin": true
}

簽名:將頭部與載荷分別采用base64編碼后,用“.”相連,再加入鹽,最后使用頭部宣告的編碼型別進行編碼,就得到了簽名,通過指定的演算法生成哈希,以確保資料不會被篡改, 首先,需要指定一個密碼(secret),該密碼僅僅為保存在服務器中,并且不能向用戶公 開,然后,使用標頭中指定的簽名演算法(默認情況下為 HMAC SHA256)根據以下公式生成簽名, HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(claims), secret) 在計算出簽名哈希后,JWT 頭,有效載荷和簽名哈希的三個部分組合成一個字串,每個部分用"."分隔,就構成整個 JWT 物件,

JWT生成token的安全性分析

從JWT生成的token組成上來看,要想避免token被偽造,主要就得看簽名部分了,而簽名部分又有三部分組成,其中頭部和載荷的base64編碼,幾乎是透明的,毫無安全性可言,那么最終守護token安全的重擔就落在了加入的上面了!試想:如果生成token所用的鹽與決議token時加入的鹽是一樣的,豈不是類似于中國人民銀行把人民幣防偽技術公開了?大家可以用這個鹽來決議token,就能用來偽造token,這時,我們就需要對鹽采用非對稱加密的方式進行加密,以達到生成token與校驗token方所用的鹽不一致的安全效果!

非對稱加密RSA介紹

基本原理:同時生成兩把密鑰:私鑰和公鑰,私鑰隱秘保存,公鑰可以下發給信任客戶端私鑰加密,持有私鑰或公鑰才可以解密公鑰加密,持有私鑰才可解密 優點:安全,難以破解 缺點:演算法比較耗時,為了安全,可以接受 歷史:三位數學家Rivest、Shamir 和 Adleman 設計了一種演算法,可以實作非對稱加密,這種演算法用他們三個人的名字縮寫:RSA,

三、具體代碼實作

集中式認證流程

  • 用戶認證: 使用UsernamePasswordAuthenticationFilter過濾器中attemptAuthentication方法實作認證功能,該過濾器父類中successfulAuthentication方法實作認證成功后的操作,
  • 身份校驗: 使用BasicAuthenticationFilter過濾器中doFilterInternal方法驗證是否登錄,以決定能否進入后續過濾器,


分布式認證流程

  • 用戶認證:由于分布式專案,多數是前后端分離的架構設計,我們要滿足可以接受異步post的認證請求引數,需要修改UsernamePasswordAuthenticationFilter過濾器中attemptAuthentication方法,讓其能夠接收請求體,另外,默認successfulAuthentication方法在認證通過后,是把用戶資訊直接放入session就完事了,現在我們需要修改這個方法,在認證通過后生成token并回傳給用戶,
  • 身份校驗: 原來BasicAuthenticationFilter過濾器中doFilterInternal方法校驗用戶是否登錄,就是看session中是否有用戶資訊,我們要修改為,驗證用戶攜帶的token是否合法,并決議出用戶資訊,交給SpringSecurity,以便于后續的授權功能可以正常使用,

3.1引入依賴

<!--spring security 安全框架-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!--JWT工具依賴-->
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.0</version>
</dependency>

3.2撰寫核心配置類

Spring Security 的核心配置就是繼承 WebSecurityConfigurerAdapter 并注解@EnableWebSecurity 的配置,這個配置指明了用戶名密碼的處理方式、請求路徑、登錄、登出控制等和安全相關的配置,

package com.oyc.security.config;

import com.oyc.security.filter.TokenAuthenticationFilter;
import com.oyc.security.filter.TokenLoginFilter;
import com.oyc.security.handler.UnauthorizedEntryPoint;
import com.oyc.security.util.DefaultPasswordEncoder;
import org.springframework.beans.factory.annotation.Autowired;
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.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;

/**
 * @ClassName: TokenWebSecurityConfig
 * @Description: TokenWebSecurityConfig
 * @Author oyc
 * @Date 2021/1/18 10:57
 * @Version 1.0
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class TokenWebSecurityConfig extends WebSecurityConfigurerAdapter {
    /**
     * 密碼管理工具類
     */
    @Autowired
    private DefaultPasswordEncoder defaultPasswordEncoder;

    /**
     * 用戶服務類
     */
    @Autowired
    private UserDetailsService userDetailsService;

    /**
     * 配置設定,設定退出的地址和token
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.exceptionHandling()
                //未授權處理
                .authenticationEntryPoint(new UnauthorizedEntryPoint())
                .and().authorizeRequests()
                .anyRequest().authenticated()
                .and().csrf().disable()
                .logout().logoutUrl("/logout")
                .and()
                //.addLogoutHandler(new TokenLogoutHandler(tokenManager))
                .addFilter(new TokenLoginFilter(authenticationManager()))
                .addFilter(new TokenAuthenticationFilter(authenticationManager())).httpBasic();
    }

    /**
     * 密碼處理
     */
    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(defaultPasswordEncoder);
    }

    /**
     * 配置哪些請求不攔截
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/index**", "/api/**", "/swagger-ui.html/**");
    }
}

3.3 創建認證授權相關的工具類

(1)DefaultPasswordEncoder:密碼處理的方法

package com.oyc.security.util;

import lombok.extern.slf4j.Slf4j;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Component;

/**
 * @ClassName: DefaultPasswordEncoder
 * @Description: DefaultPasswordEncoder
 * @Author oyc
 * @Date 2021/1/18 10:58
 * @Version 1.0
 */
@Component
@Slf4j
public class DefaultPasswordEncoder extends BCryptPasswordEncoder {

    @Override
    public String encode(CharSequence rawPassword) {
        return rawPassword.toString();
    }

    @Override
    public boolean matches(CharSequence rawPassword, String encodedPassword) {
        if (rawPassword == null) {
            throw new IllegalArgumentException("rawPassword cannot be null");
        }
        if (encodedPassword == null || encodedPassword.length() == 0) {
            log.error("Empty encoded password");
            throw new IllegalArgumentException("encodedPassword is null");
        }
        return encodedPassword.equals(rawPassword);
    }
}

(2)JwtTokenUtil:token 操作的工具類

package com.oyc.security.util;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.CompressionCodecs;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import java.util.Date;

/**
 * @ClassName: TokenManager
 * @Description: TokenManager
 * @Author oyc
 * @Date 2021/1/18 10:58
 * @Version 1.0
 */
public class JwtTokenUtil {
    private static long tokenExpiration = 24 * 60 * 60 * 1000;
    private static String tokenSignKey = "123456";
    private static String userRoleKey = "userRole";

    public String createToken(String userName) {
        String token = Jwts.builder().setSubject(userName)
                .setExpiration(new Date(System.currentTimeMillis() + tokenExpiration))
                .signWith(SignatureAlgorithm.HS512, tokenSignKey).compressWith(CompressionCodecs.GZIP).compact();
        return token;
    }

    public static String createToken(String userName, String role) {
        String token = Jwts.builder().setSubject(userName)
                .claim(userRoleKey, role)
                .setExpiration(new Date(System.currentTimeMillis() + tokenExpiration))
                .signWith(SignatureAlgorithm.HS512, tokenSignKey).compressWith(CompressionCodecs.GZIP).compact();
        return token;
    }

    public static String getUserNameFromToken(String token) {
        String userName = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token).getBody().getSubject();
        return userName;
    }

    public static String getUserRoleFromToken(String token) {
        Claims claims = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token).getBody();
        return claims.get(userRoleKey).toString();
    }

}
(3)ResponseUtil :介面回應工具類
package com.oyc.security.util;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * @ClassName: ResponseUtil
 * @Description: ResponseUtil
 * @Author oyc
 * @Date 2020/12/29 20:14
 * @Version 1.0
 */
public class ResponseUtil {
    public static void out(HttpServletResponse response, Result result) {
        ObjectMapper mapper = new ObjectMapper();
        PrintWriter writer = null;
        response.setStatus(HttpStatus.OK.value());
        response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
        try {
            writer = response.getWriter();
            mapper.writeValue(writer, result);
            writer.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (writer != null) {
                writer.flush();
                writer.close();
            }
        }
    }
}

3.4 創建認證和授權的 filter

(1)TokenLoginFilter:認證的 filter
package com.oyc.security.filter;

import com.oyc.security.util.JwtTokenUtil;
import com.oyc.security.util.ResponseUtil;
import com.oyc.security.util.Result;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.util.StringUtils;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;

/**
 * @ClassName: TokenAuthenticationFilter
 * @Description: TokenAuthenticationFilter
 * @Author oyc
 * @Date 2021/1/18 10:59
 * @Version 1.0
 */
public class TokenAuthenticationFilter extends BasicAuthenticationFilter {

    public TokenAuthenticationFilter(AuthenticationManager authManager) {
        super(authManager);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        logger.info("=================" + request.getRequestURI());
        //不需要鑒權
        if (request.getRequestURI().indexOf("index") != -1) {
            chain.doFilter(request, response);
        }
        UsernamePasswordAuthenticationToken authentication = null;
        try {
            authentication = getAuthentication(request);
        } catch (Exception e) {
            ResponseUtil.out(response, Result.error(e.getMessage()));
        }
        if (authentication != null) {
            SecurityContextHolder.getContext().setAuthentication(authentication);
        } else {
            ResponseUtil.out(response, Result.error("鑒權失敗"));
        }
        chain.doFilter(request, response);
    }

    private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
        // 獲取Token字串,token 置于 header 里
        String token = request.getHeader("token");
        if (!StringUtils.hasText(token)) {
            token = request.getParameter("token");
        }
        if (token != null && !"".equals(token.trim())) {
            // 從Token中解密獲取用戶名
            String userName = JwtTokenUtil.getUserNameFromToken(token);

            if (userName != null) {
                // 從Token中解密獲取用戶角色
                String role = JwtTokenUtil.getUserRoleFromToken(token);
                // 將ROLE_XXX,ROLE_YYY格式的角色字串轉換為陣列
                String[] roles = role.split(",");
                Collection<SimpleGrantedAuthority> authorities = new ArrayList<>();
                for (String s : roles) {
                    authorities.add(new SimpleGrantedAuthority(s));
                }
                return new UsernamePasswordAuthenticationToken(userName, token, authorities);
            }
            return null;
        }
        return null;
    }
}
(2)TokenAuthenticationFilter:授權 filter
package com.oyc.security.filter;

import com.oyc.security.util.JwtTokenUtil;
import com.oyc.security.util.ResponseUtil;
import com.oyc.security.util.Result;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.util.StringUtils;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;

/**
 * @ClassName: TokenAuthenticationFilter
 * @Description: TokenAuthenticationFilter
 * @Author oyc
 * @Date 2021/1/18 10:59
 * @Version 1.0
 */
public class TokenAuthenticationFilter extends BasicAuthenticationFilter {

    public TokenAuthenticationFilter(AuthenticationManager authManager) {
        super(authManager);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        logger.info("=================" + request.getRequestURI());
        //不需要鑒權
        if (request.getRequestURI().indexOf("index") != -1) {
            chain.doFilter(request, response);
        }
        UsernamePasswordAuthenticationToken authentication = null;
        try {
            authentication = getAuthentication(request);
        } catch (Exception e) {
            ResponseUtil.out(response, Result.error(e.getMessage()));
        }
        if (authentication != null) {
            SecurityContextHolder.getContext().setAuthentication(authentication);
        } else {
            ResponseUtil.out(response, Result.error("鑒權失敗"));
        }
        chain.doFilter(request, response);
    }

    private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
        // 獲取Token字串,token 置于 header 里
        String token = request.getHeader("token");
        if (!StringUtils.hasText(token)) {
            token = request.getParameter("token");
        }
        if (token != null && !"".equals(token.trim())) {
            // 從Token中解密獲取用戶名
            String userName = JwtTokenUtil.getUserNameFromToken(token);

            if (userName != null) {
                // 從Token中解密獲取用戶角色
                String role = JwtTokenUtil.getUserRoleFromToken(token);
                // 將ROLE_XXX,ROLE_YYY格式的角色字串轉換為陣列
                String[] roles = role.split(",");
                Collection<SimpleGrantedAuthority> authorities = new ArrayList<>();
                for (String s : roles) {
                    authorities.add(new SimpleGrantedAuthority(s));
                }
                return new UsernamePasswordAuthenticationToken(userName, token, authorities);
            }
            return null;
        }
        return null;
    }
}

3.5 UnauthorizedEntryPoint:未授權統一處理handler

public class UnauthorizedEntryPoint implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        ResponseUtil.out(response, Result.error("未授權統一處理"));
    }
}

3.6 測驗控制類

package com.oyc.security.controller;

import org.springframework.security.access.annotation.Secured;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @ClassName: TestController
 * @Description: TestController
 * @Author oyc
 * @Date 2021/1/18 11:06
 * @Version 1.0
 */
@RestController
public class TestController {

    @GetMapping(value = {"", "welcome"})
    public String welcome() {
        return "Welcome!!!";
    }

    @GetMapping("index")
    public String index() {
        return "index!!!";
    }

    @GetMapping("admin")
    public String admin() {
        return "admin!!!";
    }

    @GetMapping("user")
    public String user() {
        return "user!!!";
    }

    @GetMapping("customer")
    public String customer() {
        return "customer!!!";
    }

    /**
     * 方法執行前鑒權
     *
     * @return
     */
    @GetMapping("roleAdmin")
    @Secured("ROLE_ADMIN")
    public String roleAdmin() {
        return "roleAdmin!!!";
    }

    /**
     * 方法執行前鑒權
     *
     * @return
     */
    @GetMapping("preAuthorize")
    @PostAuthorize("hasAnyRole('ROLE_ADMIN')")
    public String preAuthorize() {
        System.out.println("preAuthorize…………");
        return "preAuthorize!!!";
    }

    /**
     * 方法執行完再鑒權
     *
     * @return
     */
    @GetMapping("postAuthorize")
    @PostAuthorize("hasAnyRole('ROLE_USER')")
    public String postAuthorize() {
        System.out.println("postAuthorize…………");
        return "PostAuthorize!!!";
    }
}

3.7 測驗

登錄回傳token:

校驗登錄狀態:

四、SpringSecurity 原理總結

4.1 SpringSecurity 的過濾器介紹
SpringSecurity 采用的是責任鏈的設計模式,它有一條很長的過濾器鏈,現在對這條過濾器鏈的 15 個過濾器進行說明:
(1) WebAsyncManagerIntegrationFilter:將 Security 背景關系與 Spring Web 中用于處理異步請求映射的 WebAsyncManager 進行集成,
(2) SecurityContextPersistenceFilter:在每次請求處理之前將該請求相關的安全背景關系資訊加載到 SecurityContextHolder 中,然后在該次請求處理完成之后,將SecurityContextHolder 中關于這次請求的資訊存盤到一個“倉儲”中,然后將SecurityContextHolder 中的資訊清除,例如在 Session 中維護一個用戶的安全信 息就是這個過濾器處理的,
(3) HeaderWriterFilter:用于將頭資訊加入回應中,
(4) CsrfFilter:用于處理跨站請求偽造,
(5)LogoutFilter:用于處理退出登錄,
(6)UsernamePasswordAuthenticationFilter:用于處理基于表單的登錄請求,從表單中獲取用戶名和密碼,默認情況下處理來自 /login 的請求,從表單中獲取用戶名和密碼時,默認使用的表單 name 值為 username 和 password,這兩個值可以通過設定這個過濾器的 usernameParameter 和 passwordParameter 兩個引數的值進行修改,
(7)DefaultLoginPageGeneratingFilter:如果沒有配置登錄頁面,那系統初始化時就會配置這個過濾器,并且用于在需要進行登錄時生成一個登錄表單頁面,
(8)BasicAuthenticationFilter:檢測和處理 http basic 認證,
(9)RequestCacheAwareFilter:用來處理請求的快取,
(10)SecurityContextHolderAwareRequestFilter:主要是包裝請求物件 request,
(11)AnonymousAuthenticationFilter:檢測 SecurityContextHolder 中是否存在
Authentication 物件,如果不存在為其提供一個匿名 Authentication,
(12)SessionManagementFilter:管理 session 的過濾器
(13)ExceptionTranslationFilter:處理 AccessDeniedException 和
AuthenticationException 例外,
(14)FilterSecurityInterceptor:可以看做過濾器鏈的出口,
(15)RememberMeAuthenticationFilter:當用戶沒有登錄而直接訪問資源時, 從 cookie里找出用戶的資訊, 如果 Spring Security 能夠識別出用戶提供的 remember me cookie, 用戶將不必填寫用戶名和密碼, 而是直接登錄進入系統,該過濾器默認不開啟,
4.2 SpringSecurity 基本流程
Spring Security 采取過濾鏈實作認證與授權,只有當前過濾器通過,才能進入下一個
過濾器:

綠色部分是認證過濾器,需要我們自己配置,可以配置多個認證過濾器,認證過濾器可以使用 Spring Security 提供的認證過濾器,也可以自定義過濾器(例如:短信驗證),認證過濾器要在 configure(HttpSecurity http)方法中配置,沒有配置不生效,下面會重點介紹以下三個過濾器:

UsernamePasswordAuthenticationFilter 過濾器:該過濾器會攔截前端提交的 POST 方式的登錄表單請求,并進行身份認證,

ExceptionTranslationFilter 過濾器:該過濾器不需要我們配置,對于前端提交的請求會直接放行,捕獲后續拋出的例外并進行處理(例如:權限訪問限制),
FilterSecurityInterceptor 過濾器:該過濾器是過濾器鏈的最后一個過濾器,根據資源權限配置來判斷當前請求是否有權限訪問對應的資源,如果訪問受限會拋出相關例外,并由 ExceptionTranslationFilter 過濾器進行捕獲和處理,
4.3 SpringSecurity 認證流程
認證流程是在 UsernamePasswordAuthenticationFilter 過濾器中處理的,具體流程如下
所示:

對應原始碼:https://github.com/oycyqr/springboot-learning-demo/tree/master/springboot-security-token

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/250636.html

標籤:其他

上一篇:Java 移除List中的元素,這玩意講究!

下一篇:Vue與SpringBoot專案中token的工程化使用

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more