亚洲国产日韩欧美一区二区三区,精品亚洲国产成人av在线,国产99视频精品免视看7,99国产精品久久久久久久成人热,欧美日韩亚洲国产综合乱

首頁(yè) Java java教程 了解 Spring Security 和 OAuth

了解 Spring Security 和 OAuth

Jan 14, 2025 pm 04:05 PM

在本文中,我們將探索 Spring 安全性,并使用 OAuth 2.0 構(gòu)建一個(gè)身份驗(yàn)證系統(tǒng)。

Spring Security 是一個(gè)功能強(qiáng)大、高度可定制的框架,用于在基于 Java 的應(yīng)用程序中實(shí)現(xiàn)強(qiáng)大的身份驗(yàn)證和訪問(wèn)控制機(jī)制。它是 Spring 生態(tài)系統(tǒng)的核心組件,廣泛用于保護(hù) Web 應(yīng)用程序、REST API 和其他后端服務(wù)的安全。借助 Spring Security,您可以為在應(yīng)用程序中構(gòu)建和實(shí)施安全實(shí)踐奠定堅(jiān)實(shí)的基礎(chǔ)。


Spring Security 的工作原理

在深入了解 Spring Security 的運(yùn)行方式之前,了解基于 Java 的 Web 服務(wù)器中的請(qǐng)求處理生命周期至關(guān)重要。 Spring Security 無(wú)縫集成到此生命周期中以保護(hù)傳入請(qǐng)求。


使用 Spring Security 處理請(qǐng)求生命周期

使用 Spring Security 在基于 Spring 的應(yīng)用程序中處理 HTTP 請(qǐng)求的生命周期涉及多個(gè)階段,每個(gè)階段在處理、驗(yàn)證和保護(hù)請(qǐng)求方面都發(fā)揮著關(guān)鍵作用。


1. 客戶請(qǐng)求

當(dāng)客戶端(例如瀏覽器、移動(dòng)應(yīng)用程序或 Postman 等 API 工具)向服務(wù)器發(fā)送 HTTP 請(qǐng)求時(shí),生命周期就開(kāi)始了。

示例:

GET /api/admin/dashboard HTTP/1.1


2. Servlet 容器

Servlet 容器(例如 Tomcat)接收請(qǐng)求并將其委托給 DispatcherServlet(Spring 應(yīng)用程序中的前端控制器)。這是應(yīng)用程序處理管道開(kāi)始的地方。


3. Spring Security 過(guò)濾器鏈

在 DispatcherServlet 處理請(qǐng)求之前,Spring Security 的過(guò)濾器鏈 會(huì)攔截它。過(guò)濾器鏈?zhǔn)且幌盗羞^(guò)濾器,每個(gè)過(guò)濾器負(fù)責(zé)處理特定的安全任務(wù)。這些過(guò)濾器確保請(qǐng)求在到達(dá)應(yīng)用程序邏輯之前滿足身份驗(yàn)證和授權(quán)要求。

鏈中的關(guān)鍵過(guò)濾器

  1. 身份驗(yàn)證過(guò)濾器:

    這些過(guò)濾器驗(yàn)證請(qǐng)求是否包含有效的憑據(jù),例如用戶名/密碼、JWT 或會(huì)話 cookie。

  2. 授權(quán)過(guò)濾器

    身份驗(yàn)證后,這些過(guò)濾器確保經(jīng)過(guò)身份驗(yàn)證的用戶具有訪問(wèn)所請(qǐng)求資源所需的角色或權(quán)限。

  3. 其他濾鏡

* **CsrfFilter**: Validates CSRF tokens to prevent Cross-Site Request Forgery attacks.

* **CorsFilter**: Manages Cross-Origin Resource Sharing (CORS) rules for secure API access from different domains.

* **ExceptionTranslationFilter**: Handles security-related exceptions (e.g., invalid credentials) and sends appropriate responses to the client.

4. 安全上下文

如果身份驗(yàn)證成功,Spring Security 將創(chuàng)建一個(gè) Authentication 對(duì)象并將其存儲(chǔ)在 SecurityContext 中。該對(duì)象通常存儲(chǔ)在線程本地存儲(chǔ)中,在整個(gè)請(qǐng)求生命周期中都可以訪問(wèn)。

身份驗(yàn)證對(duì)象

  • Principal:代表經(jīng)過(guò)身份驗(yàn)證的用戶(例如用戶名)。

  • 憑據(jù):包括 JWT 令牌或密碼等身份驗(yàn)證詳細(xì)信息。

  • 權(quán)限:包含分配給用戶的角色和權(quán)限。

過(guò)濾器鏈中的示例流程

  • 請(qǐng)求通過(guò)身份驗(yàn)證過(guò)濾器。

  • 如果憑據(jù)有效,則會(huì)創(chuàng)建 Authentication 對(duì)象并將其添加到 SecurityContext。

  • 如果憑據(jù)無(wú)效,ExceptionTranslationFilter 會(huì)向客戶端發(fā)送 401 未經(jīng)授權(quán)的響應(yīng)。


5. DispatcherServlet

一旦請(qǐng)求成功通過(guò) Spring Security 過(guò)濾器鏈,DispatcherServlet 就會(huì)接管:

  1. 處理程序映射:

    它根據(jù) URL 和 HTTP 方法將傳入請(qǐng)求映射到適當(dāng)?shù)目刂破鞣椒ā?/p>

  2. 控制器調(diào)用:

    映射的控制器通常在服務(wù)和存儲(chǔ)庫(kù)等其他 Spring 組件的幫助下處理請(qǐng)求并返回適當(dāng)?shù)捻憫?yīng)。

Spring Security 如何融入生命周期

Spring Security 通過(guò)其過(guò)濾器將自身集成到此生命周期中,在最早階段攔截請(qǐng)求。當(dāng)請(qǐng)求到達(dá)應(yīng)用程序邏輯時(shí),它已經(jīng)經(jīng)過(guò)身份驗(yàn)證和授權(quán),確保核心應(yīng)用程序僅處理合法流量。


Spring Security 的設(shè)計(jì)確保以聲明方式處理身份驗(yàn)證、授權(quán)和其他安全措施,使開(kāi)發(fā)人員能夠根據(jù)需要靈活地自定義或擴(kuò)展其行為。它不僅強(qiáng)制執(zhí)行最佳實(shí)踐,還簡(jiǎn)化了現(xiàn)代應(yīng)用程序中復(fù)雜安全要求的實(shí)現(xiàn)。

Understanding Spring Security and OAuth

Spring Security 組件:超越過(guò)濾器鏈

探索了 Spring Security 中的過(guò)濾器鏈之后,讓我們深入研究一些在身份驗(yàn)證和授權(quán)過(guò)程中發(fā)揮關(guān)鍵作用的其他關(guān)鍵組件。

認(rèn)證管理器

AuthenticationManager 是一個(gè)定義單個(gè)方法的接口,authenticate(Authenticationauthentication),用于驗(yàn)證用戶的憑據(jù)并確定它們是否有效。您可以將 AuthenticationManager 視為一個(gè)協(xié)調(diào)器,您可以在其中注冊(cè)多個(gè)提供商,并且根據(jù)請(qǐng)求類型,它將向正確的提供商發(fā)送身份驗(yàn)證請(qǐng)求。

認(rèn)證提供者

AuthenticationProvider 是一個(gè)接口,它定義了一個(gè)合約,用于根據(jù)用戶的憑據(jù)對(duì)用戶進(jìn)行身份驗(yàn)證。它代表特定的身份驗(yàn)證機(jī)制,例如用戶名/密碼、OAuth 或 LDAP。多個(gè) AuthenticationProvider 實(shí)現(xiàn)可以共存,允許應(yīng)用程序支持各種身份驗(yàn)證策略。

核心概念

  1. 身份驗(yàn)證對(duì)象:

    AuthenticationProvider 處理 Authentication 對(duì)象,該對(duì)象封裝了用戶的憑據(jù)(例如用戶名和密碼)。

  2. 驗(yàn)證方法:

    每個(gè) AuthenticationProvider 都實(shí)現(xiàn)了authenticate(Authenticationauthentication)方法,實(shí)際的身份驗(yàn)證邏輯駐留在其中。此方法:

* **CsrfFilter**: Validates CSRF tokens to prevent Cross-Site Request Forgery attacks.

* **CorsFilter**: Manages Cross-Origin Resource Sharing (CORS) rules for secure API access from different domains.

* **ExceptionTranslationFilter**: Handles security-related exceptions (e.g., invalid credentials) and sends appropriate responses to the client.
  1. 支持方法: support(Class>authentication) 方法指示 AuthenticationProvider 是否可以處理給定類型的身份驗(yàn)證。這允許 Spring Security 確定正確的提供者來(lái)處理特定的身份驗(yàn)證請(qǐng)求。

示例

  • 數(shù)據(jù)庫(kù)支持的 AuthenticationProvider 驗(yàn)證用戶名和密碼。

  • 基于 OAuth 的 AuthenticationProvider 驗(yàn)證外部身份提供商頒發(fā)的令牌。

用戶詳情服務(wù)

UserDetailsS??ervice 在 Spring 文檔中被描述為加載用戶特定數(shù)據(jù)的核心接口,它包含一個(gè)方法 loadUserByUsername ,該方法接受用戶名作為參數(shù)并返回 ==User== 身份對(duì)象?;旧衔覀儎?chuàng)建并實(shí)現(xiàn)了 UserDetailsS??ervice 的類,在其中重寫了 loadUserByUsername 方法。

* Validates the user’s credentials.

* Returns an authenticated `Authentication` object upon success.

* Throws an `AuthenticationException` if authentication fails.

現(xiàn)在這三者如何協(xié)同工作的是 AuthenticationManager 會(huì)要求 AuthenticationProvider 根據(jù)指定的 Provider 類型進(jìn)行身份驗(yàn)證,而 UserDetailsS??ervice 實(shí)現(xiàn)將幫助 AuthenticationProvider 證明用戶詳細(xì)信息。

現(xiàn)在,在進(jìn)行配置和所有內(nèi)容之前,這里是基于 JWT 身份驗(yàn)證的 Spring Security 的簡(jiǎn)明流程:

1. 用戶請(qǐng)求

  • 用戶使用其憑據(jù)(用戶名和密碼)或 JWT 令牌(標(biāo)頭中)向經(jīng)過(guò)身份驗(yàn)證的端點(diǎn)發(fā)送請(qǐng)求,并將請(qǐng)求傳遞到身份驗(yàn)證過(guò)濾器

  • AuthenticationFilter(例如,UsernamePasswordAuthenticationFilter):

    • 根據(jù)提交的憑據(jù)(通常以用戶名和密碼的形式)處理用戶身份驗(yàn)證。這就是 UsernamePasswordAuthenticationFilter 發(fā)揮作用的地方。
    • 它監(jiān)聽(tīng)請(qǐng)求,提取用戶名和密碼,并將它們傳遞給 AuthenticationManager。
    • 但是我們沒(méi)有傳遞用戶名和密碼,我們只給出令牌,因此在此 AuthenticationFilter 之前應(yīng)該有一個(gè)過(guò)濾器,它將告訴身份驗(yàn)證過(guò)程用戶已通過(guò)身份驗(yàn)證,無(wú)需檢查用戶名和密碼,這通過(guò)創(chuàng)建 JWTFilter
    • 來(lái)完成

2.JWT過(guò)濾器

這個(gè)自定義過(guò)濾器擴(kuò)展了 OncePerRequestFilter 并放置在 UsernamePasswordAuthenticationFilter 之前,它的作用是從請(qǐng)求中提取令牌并驗(yàn)證它。

如果令牌有效,它會(huì)創(chuàng)建一個(gè) UsernamePasswordAuthenticationToken 并將該令牌設(shè)置到安全上下文中,告訴 Spring Security 該請(qǐng)求已通過(guò)身份驗(yàn)證,并且當(dāng)此請(qǐng)求傳遞到 UsernamePasswordAuthenticationFilter 時(shí),它只是傳遞,因?yàn)樗哂?UsernamePasswordAuthenticationToken

* **CsrfFilter**: Validates CSRF tokens to prevent Cross-Site Request Forgery attacks.

* **CorsFilter**: Manages Cross-Origin Resource Sharing (CORS) rules for secure API access from different domains.

* **ExceptionTranslationFilter**: Handles security-related exceptions (e.g., invalid credentials) and sends appropriate responses to the client.

如果我們?cè)?UserDetails 類的幫助下驗(yàn)證用戶名和密碼后傳遞了用戶名和密碼而不是令牌,則此 UsernamePasswordAuthenticationToken 是在 AuthenticationManager 和 AuthenticationProvider 的幫助下生成的。

3. 身份驗(yàn)證管理器

  • AuthenticationManager:它接收身份驗(yàn)證請(qǐng)求并將其委托給我們配置的適當(dāng)?shù)?AuthenticationProvider。
* Validates the user’s credentials.

* Returns an authenticated `Authentication` object upon success.

* Throws an `AuthenticationException` if authentication fails.

4. 身份驗(yàn)證提供程序

  • UserDetailsS??ervice:AuthenticationProvider 使用 UserDetailsS??ervice 根據(jù)用戶名加載用戶詳細(xì)信息。我們?yōu)榇颂峁┝?UserDetailsS??ervice

  • 的實(shí)現(xiàn)
  • 憑證驗(yàn)證:它將提供的密碼與存儲(chǔ)在用戶詳細(xì)信息中的密碼進(jìn)行比較(通常使用密碼編碼器)。

package com.oauth.backend.services;

import com.oauth.backend.entities.User;
import com.oauth.backend.repositories.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;


@Component
public class CustomUserDetailsService implements UserDetailsService {
    private final UserRepository userRepository;

    public CustomUserDetailsService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        User user = userRepository.findByUsername(username);
        if(user==null){
            throw new UsernameNotFoundException(username);
        }
        return new UserDetailsImpl(user);
    }
    public UserDetails loadUserByEmail(String email) throws UsernameNotFoundException {
        User user = userRepository.findByEmail(email);
        if(user==null){
            throw new UsernameNotFoundException(email);
        }
        return new UserDetailsImpl(user);
    }
}

現(xiàn)在需要配置所有這些不同的過(guò)濾器和 bean,以便 Spring security 知道要做什么,因此我們創(chuàng)建一個(gè)配置類,在其中指定所有配置。

@Component
public class JWTFilter extends OncePerRequestFilter {

    private final JWTService jwtService;
    private final UserDetailsService userDetailsService;
    public JWTFilter(JWTService jwtService,UserDetailsService userDetailsService) {
        this.jwtService = jwtService;
        this.userDetailsService = userDetailsService;
    }
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        final String authHeader = request.getHeader("Authorization");

        if(authHeader == null || !authHeader.startsWith("Bearer")) {
            filterChain.doFilter(request,response);
            return;
        }

        final String jwt = authHeader.substring(7);
        final String userName = jwtService.extractUserName(jwt);

        Authentication authentication
                = SecurityContextHolder.getContext().getAuthentication();

        if(userName !=null  && authentication == null) {
            //Authenticate
            UserDetails userDetails
                    = userDetailsService.loadUserByUsername(userName);

            if(jwtService.isTokenValid(jwt,userDetails)) {
                UsernamePasswordAuthenticationToken authenticationToken
                        = new UsernamePasswordAuthenticationToken(
                        userDetails,
                        null,
                        userDetails.getAuthorities()
                );

                SecurityContextHolder.getContext()
                        .setAuthentication(authenticationToken);
            }
        }

        filterChain.doFilter(request,response);
    }



}

到目前為止,我們已經(jīng)在 Spring Security 的幫助下理解并配置了我們的身份驗(yàn)證,現(xiàn)在是時(shí)候測(cè)試它了。

我們將創(chuàng)建一個(gè)簡(jiǎn)單的應(yīng)用程序,其中包含兩個(gè)控制器 AuthController(處理登錄和注冊(cè))和 ProductController(虛擬受保護(hù)控制器)

* **CsrfFilter**: Validates CSRF tokens to prevent Cross-Site Request Forgery attacks.

* **CorsFilter**: Manages Cross-Origin Resource Sharing (CORS) rules for secure API access from different domains.

* **ExceptionTranslationFilter**: Handles security-related exceptions (e.g., invalid credentials) and sends appropriate responses to the client.
* Validates the user’s credentials.

* Returns an authenticated `Authentication` object upon success.

* Throws an `AuthenticationException` if authentication fails.
package com.oauth.backend.services;

import com.oauth.backend.entities.User;
import com.oauth.backend.repositories.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;


@Component
public class CustomUserDetailsService implements UserDetailsService {
    private final UserRepository userRepository;

    public CustomUserDetailsService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        User user = userRepository.findByUsername(username);
        if(user==null){
            throw new UsernameNotFoundException(username);
        }
        return new UserDetailsImpl(user);
    }
    public UserDetails loadUserByEmail(String email) throws UsernameNotFoundException {
        User user = userRepository.findByEmail(email);
        if(user==null){
            throw new UsernameNotFoundException(email);
        }
        return new UserDetailsImpl(user);
    }
}
@Component
public class JWTFilter extends OncePerRequestFilter {

    private final JWTService jwtService;
    private final UserDetailsService userDetailsService;
    public JWTFilter(JWTService jwtService,UserDetailsService userDetailsService) {
        this.jwtService = jwtService;
        this.userDetailsService = userDetailsService;
    }
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        final String authHeader = request.getHeader("Authorization");

        if(authHeader == null || !authHeader.startsWith("Bearer")) {
            filterChain.doFilter(request,response);
            return;
        }

        final String jwt = authHeader.substring(7);
        final String userName = jwtService.extractUserName(jwt);

        Authentication authentication
                = SecurityContextHolder.getContext().getAuthentication();

        if(userName !=null  && authentication == null) {
            //Authenticate
            UserDetails userDetails
                    = userDetailsService.loadUserByUsername(userName);

            if(jwtService.isTokenValid(jwt,userDetails)) {
                UsernamePasswordAuthenticationToken authenticationToken
                        = new UsernamePasswordAuthenticationToken(
                        userDetails,
                        null,
                        userDetails.getAuthorities()
                );

                SecurityContextHolder.getContext()
                        .setAuthentication(authenticationToken);
            }
        }

        filterChain.doFilter(request,response);
    }



}
@Bean  
public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception{  
return config.getAuthenticationManager();  
}
@Bean  
public AuthenticationProvider authenticationProvider(){  
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();  
authenticationProvider.setUserDetailsService(userDetailsServiceImpl);  
authenticationProvider.setPasswordEncoder(passwordEncoder);  
return authenticationProvider;  
}

到目前為止,我們已經(jīng)實(shí)現(xiàn)了注冊(cè)、登錄和驗(yàn)證,但是如果我還想添加 Login With Google/Github 功能,那么我們可以借助 OAuth2.0 來(lái)實(shí)現(xiàn)

OAuth 2.0

OAuth 2.0 是一種用于授權(quán)的協(xié)議,通過(guò)它,用戶可以授予第三方應(yīng)用程序訪問(wèn)存儲(chǔ)在其他平臺(tái)(例如 Google Drive、Github)上的資源的權(quán)限,而無(wú)需共享這些平臺(tái)的憑據(jù)。

它主要用于啟用社交登錄,例如“使用 google 登錄”、“使用 github 登錄”。

Google、Facebook、Github 等平臺(tái)提供了授權(quán)服務(wù)器,該服務(wù)器實(shí)現(xiàn)了 OAuth 2.0 協(xié)議,用于此社交登錄或授權(quán)訪問(wèn)。

OAuth 2.0 的關(guān)鍵概念

  • 資源所有者

  • 客戶

  • 授權(quán)服務(wù)器

  • 資源服務(wù)器

  • 訪問(wèn)令牌

  • 范圍

  • 補(bǔ)助金

現(xiàn)在我們將一一研究每個(gè)概念

資源所有者

資源所有者是想要授權(quán)第三方應(yīng)用程序(您的應(yīng)用程序)的用戶。

客戶

這是您的(第三方)應(yīng)用程序想要從資源服務(wù)器訪問(wèn)數(shù)據(jù)或資源。

資源服務(wù)器

它是存儲(chǔ)用戶數(shù)據(jù)的服務(wù)器,供第三方應(yīng)用程序訪問(wèn)。

授權(quán)服務(wù)器

對(duì)資源所有者進(jìn)行身份驗(yàn)證并向客戶端(例如 Google 帳戶)頒發(fā)訪問(wèn)令牌的服務(wù)器。

訪問(wèn)令牌

授權(quán)服務(wù)器向客戶端頒發(fā)的憑證,允許客戶端代表用戶訪問(wèn)資源服務(wù)器。它的生命周期通常很短,很快就會(huì)過(guò)期,因此還提供了刷新令牌來(lái)刷新此訪問(wèn)令牌,以便用戶不需要再次授權(quán)。

范圍

用戶授予的特定權(quán)限,定義客戶端可以和不能對(duì)用戶數(shù)據(jù)執(zhí)行什么操作。例如,對(duì)于授權(quán),我們只需要用戶信息,如個(gè)人資料、姓名等,但對(duì)于文件訪問(wèn),需要不同的范圍。

補(bǔ)助金

客戶端應(yīng)用程序從授權(quán)服務(wù)器獲取訪問(wèn)令牌的方法。授權(quán)定義了授權(quán)客戶端應(yīng)用程序訪問(wèn)資源所有者的受保護(hù)數(shù)據(jù)的流程和條件。

它是安全的,因?yàn)槲覀儾恍枰驗(yàn)g覽器公開(kāi)我們的客戶端密鑰和其他憑據(jù)

OAuth 2.0 提供了兩種最常用的 Grant 類型

  1. 授權(quán)碼授予

    它是最常用的授權(quán)/方法類型,最安全,并且適用于服務(wù)器端應(yīng)用程序

    在此,授權(quán)碼由客戶端提供給后端,后端將訪問(wèn)令牌提供給客戶端。

    流程:

    1. 客戶端將用戶重定向到授權(quán)服務(wù)器。
    2. 用戶登錄并同意。
    3. 授權(quán)服務(wù)器發(fā)出授權(quán)碼。
    4. 客戶端與后端交換授權(quán)代碼以獲取訪問(wèn)令牌。
  2. 隱性授予

    由單頁(yè)應(yīng)用程序 (SPA) 或沒(méi)有后端的應(yīng)用程序使用。在此,訪問(wèn)令牌是在瀏覽器本身中直接生成和頒發(fā)的。

    流程:

    1. 客戶端將用戶重定向到授權(quán)服務(wù)器。
    2. 用戶登錄并同意。
    3. 授權(quán)服務(wù)器直接頒發(fā)訪問(wèn)令牌。

為了完全理解,我們將分別實(shí)現(xiàn)兩者,但首先我們將實(shí)現(xiàn)我們需要的授權(quán)代碼授予

  1. 授權(quán)服務(wù)器

    它可以是任何一個(gè)平臺(tái)(例如 google 、 github),或者您也可以使用 KeyCloak 創(chuàng)建自己的平臺(tái),或者也可以遵循 OAuth 2.0 標(biāo)準(zhǔn)構(gòu)建您自己的平臺(tái)(我們可能會(huì)在下一篇博客中這樣做?)

  2. Spring Boot 應(yīng)用

    這將是我們的主要后端應(yīng)用程序/服務(wù),它將處理代碼交換、驗(yàn)證、保存用戶詳細(xì)信息和分配 JWT 令牌等所有操作

  3. React 應(yīng)用程序(前端)

    這將是我們的客戶端,它將用戶重定向到授權(quán)服務(wù)器進(jìn)行授權(quán)。

因此,在我們的實(shí)現(xiàn)中,我們要做的是前端(網(wǎng)絡(luò)/應(yīng)用程序)將我們的用戶重定向到谷歌登錄,并將 uri 重定向到我們的后端端點(diǎn),這將進(jìn)一步控制我們稍后將討論它以及redirect_url我們還傳遞應(yīng)用程序的客戶端 ID,所有這些都將在查詢參數(shù)中發(fā)送。

否,當(dāng)用戶成功登錄谷歌時(shí),授權(quán)服務(wù)器(谷歌的)會(huì)將我們的請(qǐng)求重定向到后端端點(diǎn),我們要做的就是與授權(quán)服務(wù)器交換授權(quán)代碼以獲取訪問(wèn)令牌和刷新令牌,然后我們可以根據(jù)需要處理身份驗(yàn)證,最后我們會(huì)將響應(yīng)發(fā)送回我們的前端,該前端將有一個(gè) cookie 并重定向到我們的儀表板,或者可能是受保護(hù)的頁(yè)面。

現(xiàn)在我們將研究代碼,但請(qǐng)確保在 OAuth 客戶端的 Google 控制臺(tái)儀表板中的授權(quán)重定向 URL 中添加后端端點(diǎn)的 URL。

* **CsrfFilter**: Validates CSRF tokens to prevent Cross-Site Request Forgery attacks.

* **CorsFilter**: Manages Cross-Origin Resource Sharing (CORS) rules for secure API access from different domains.

* **ExceptionTranslationFilter**: Handles security-related exceptions (e.g., invalid credentials) and sends appropriate responses to the client.

就是這樣,它可以正常工作,為了測(cè)試,您可以制作一個(gè)簡(jiǎn)單的前端應(yīng)用程序,它除了具有上下文之外什么都沒(méi)有,而您不知道登錄和注冊(cè)功能。

感謝您閱讀這么久,如果您有任何建議,請(qǐng)?jiān)谠u(píng)論中提出

以上是了解 Spring Security 和 OAuth的詳細(xì)內(nèi)容。更多信息請(qǐng)關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

本站聲明
本文內(nèi)容由網(wǎng)友自發(fā)貢獻(xiàn),版權(quán)歸原作者所有,本站不承擔(dān)相應(yīng)法律責(zé)任。如您發(fā)現(xiàn)有涉嫌抄襲侵權(quán)的內(nèi)容,請(qǐng)聯(lián)系admin@php.cn

熱AI工具

Undress AI Tool

Undress AI Tool

免費(fèi)脫衣服圖片

Undresser.AI Undress

Undresser.AI Undress

人工智能驅(qū)動(dòng)的應(yīng)用程序,用于創(chuàng)建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用于從照片中去除衣服的在線人工智能工具。

Clothoff.io

Clothoff.io

AI脫衣機(jī)

Video Face Swap

Video Face Swap

使用我們完全免費(fèi)的人工智能換臉工具輕松在任何視頻中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費(fèi)的代碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

功能強(qiáng)大的PHP集成開(kāi)發(fā)環(huán)境

Dreamweaver CS6

Dreamweaver CS6

視覺(jué)化網(wǎng)頁(yè)開(kāi)發(fā)工具

SublimeText3 Mac版

SublimeText3 Mac版

神級(jí)代碼編輯軟件(SublimeText3)

Java中可呼叫和可運(yùn)行的差異 Java中可呼叫和可運(yùn)行的差異 Jul 04, 2025 am 02:50 AM

Callable和Runnable在Java中主要有三點(diǎn)區(qū)別。第一,Callable的call()方法可以返回結(jié)果,適合需要返回值的任務(wù),如Callable;而Runnable的run()方法無(wú)返回值,適用于無(wú)需返回的任務(wù),如日志記錄。第二,Callable允許拋出checked異常,便于錯(cuò)誤傳遞;而Runnable必須在內(nèi)部處理異常。第三,Runnable可直接傳給Thread或ExecutorService,而Callable只能提交給ExecutorService,并返回Future對(duì)象以

現(xiàn)代爪哇的異步編程技術(shù) 現(xiàn)代爪哇的異步編程技術(shù) Jul 07, 2025 am 02:24 AM

Java支持異步編程的方式包括使用CompletableFuture、響應(yīng)式流(如ProjectReactor)以及Java19 中的虛擬線程。1.CompletableFuture通過(guò)鏈?zhǔn)秸{(diào)用提升代碼可讀性和維護(hù)性,支持任務(wù)編排和異常處理;2.ProjectReactor提供Mono和Flux類型實(shí)現(xiàn)響應(yīng)式編程,具備背壓機(jī)制和豐富的操作符;3.虛擬線程減少并發(fā)成本,適用于I/O密集型任務(wù),與傳統(tǒng)平臺(tái)線程相比更輕量且易于擴(kuò)展。每種方式均有適用場(chǎng)景,應(yīng)根據(jù)需求選擇合適工具并避免混合模型以保持簡(jiǎn)潔性

了解Java Nio及其優(yōu)勢(shì) 了解Java Nio及其優(yōu)勢(shì) Jul 08, 2025 am 02:55 AM

JavaNIO是Java1.4引入的新型IOAPI,1)面向緩沖區(qū)和通道,2)包含Buffer、Channel和Selector核心組件,3)支持非阻塞模式,4)相比傳統(tǒng)IO更高效處理并發(fā)連接。其優(yōu)勢(shì)體現(xiàn)在:1)非阻塞IO減少線程開(kāi)銷,2)Buffer提升數(shù)據(jù)傳輸效率,3)Selector實(shí)現(xiàn)多路復(fù)用,4)內(nèi)存映射加快文件讀寫。使用時(shí)需注意:1)Buffer的flip/clear操作易混淆,2)非阻塞下需手動(dòng)處理不完整數(shù)據(jù),3)Selector注冊(cè)需及時(shí)取消,4)NIO并非適用于所有場(chǎng)景。

在Java中使用枚舉的最佳實(shí)踐 在Java中使用枚舉的最佳實(shí)踐 Jul 07, 2025 am 02:35 AM

在Java中,枚舉(enum)適合表示固定常量集合,最佳實(shí)踐包括:1.用enum表示固定狀態(tài)或選項(xiàng),提升類型安全和可讀性;2.為枚舉添加屬性和方法以增強(qiáng)靈活性,如定義字段、構(gòu)造函數(shù)、輔助方法等;3.使用EnumMap和EnumSet提高性能和類型安全性,因其基于數(shù)組實(shí)現(xiàn)更高效;4.避免濫用enum,如動(dòng)態(tài)值、頻繁變更或復(fù)雜邏輯場(chǎng)景應(yīng)使用其他方式替代。正確使用enum能提升代碼質(zhì)量并減少錯(cuò)誤,但需注意其適用邊界。

Java Classloader在內(nèi)部如何工作 Java Classloader在內(nèi)部如何工作 Jul 06, 2025 am 02:53 AM

Java的類加載機(jī)制通過(guò)ClassLoader實(shí)現(xiàn),其核心工作流程分為加載、鏈接和初始化三個(gè)階段。加載階段由ClassLoader動(dòng)態(tài)讀取類的字節(jié)碼并創(chuàng)建Class對(duì)象;鏈接包括驗(yàn)證類的正確性、為靜態(tài)變量分配內(nèi)存及解析符號(hào)引用;初始化則執(zhí)行靜態(tài)代碼塊和靜態(tài)變量賦值。類加載采用雙親委派模型,優(yōu)先委托父類加載器查找類,依次嘗試Bootstrap、Extension和ApplicationClassLoader,確保核心類庫(kù)安全且避免重復(fù)加載。開(kāi)發(fā)者可自定義ClassLoader,如URLClassL

探索Java中不同的同步機(jī)制 探索Java中不同的同步機(jī)制 Jul 04, 2025 am 02:53 AM

Javaprovidesmultiplesynchronizationtoolsforthreadsafety.1.synchronizedblocksensuremutualexclusionbylockingmethodsorspecificcodesections.2.ReentrantLockoffersadvancedcontrol,includingtryLockandfairnesspolicies.3.Conditionvariablesallowthreadstowaitfor

有效處理常見(jiàn)的Java例外 有效處理常見(jiàn)的Java例外 Jul 05, 2025 am 02:35 AM

Java異常處理的關(guān)鍵在于區(qū)分checked和unchecked異常并合理使用try-catch、finally及日志記錄。1.checked異常如IOException需強(qiáng)制處理,適用于可預(yù)期的外部問(wèn)題;2.unchecked異常如NullPointerException通常由程序邏輯錯(cuò)誤引起,屬于運(yùn)行時(shí)錯(cuò)誤;3.捕獲異常時(shí)應(yīng)具體明確,避免籠統(tǒng)捕獲Exception;4.推薦使用try-with-resources自動(dòng)關(guān)閉資源,減少手動(dòng)清理代碼;5.異常處理中應(yīng)結(jié)合日志框架記錄詳細(xì)信息,便于后

Hashmap在Java內(nèi)部如何工作? Hashmap在Java內(nèi)部如何工作? Jul 15, 2025 am 03:10 AM

HashMap在Java中通過(guò)哈希表實(shí)現(xiàn)鍵值對(duì)存儲(chǔ),其核心在于快速定位數(shù)據(jù)位置。1.首先使用鍵的hashCode()方法生成哈希值,并通過(guò)位運(yùn)算轉(zhuǎn)換為數(shù)組索引;2.不同對(duì)象可能產(chǎn)生相同哈希值,導(dǎo)致沖突,此時(shí)以鏈表形式掛載節(jié)點(diǎn),JDK8后鏈表過(guò)長(zhǎng)(默認(rèn)長(zhǎng)度8)則轉(zhuǎn)為紅黑樹(shù)提升效率;3.使用自定義類作鍵時(shí)必須重寫equals()和hashCode()方法;4.HashMap動(dòng)態(tài)擴(kuò)容,當(dāng)元素?cái)?shù)超過(guò)容量乘以負(fù)載因子(默認(rèn)0.75)時(shí),擴(kuò)容并重新哈希;5.HashMap非線程安全,多線程下應(yīng)使用Concu

See all articles