溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

如何用SpringSecurity查看登錄

發(fā)布時間:2021-10-11 21:57:45 來源:億速云 閱讀:175 作者:iii 欄目:開發(fā)技術(shù)

本篇內(nèi)容主要講解“如何用SpringSecurity查看登錄”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“如何用SpringSecurity查看登錄”吧!

1.Authentication

Authentication 這個接口前面和大家聊過多次,今天還要再來聊一聊。

Authentication  接口用來保存我們的登錄用戶信息,實際上,它是對主體(java.security.Principal)做了進(jìn)一步的封裝。

我們來看下 Authentication 的一個定義:

public interface Authentication extends Principal, Serializable {  Collection<? extends GrantedAuthority> getAuthorities();  Object getCredentials();  Object getDetails();  Object getPrincipal();  boolean isAuthenticated();  void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException; }

接口的解釋如下:

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2. getAuthorities 方法用來獲取用戶的權(quán)限。

  3. getCredentials 方法用來獲取用戶憑證,一般來說就是密碼。

  4. getDetails 方法用來獲取用戶攜帶的詳細(xì)信息,可能是當(dāng)前請求之類的東西。

  5. getPrincipal 方法用來獲取當(dāng)前用戶,可能是一個用戶名,也可能是一個用戶對象。

  6. isAuthenticated 當(dāng)前用戶是否認(rèn)證成功。

這里有一個比較好玩的方法,叫做 getDetails。關(guān)于這個方法,源碼的解釋如下:

Stores additional details about the authentication request. These might be an  IP address, certificate serial number etc.

從這段解釋中,我們可以看出,該方法實際上就是用來存儲有關(guān)身份認(rèn)證的其他信息的,例如 IP 地址、證書信息等等。

實際上,在默認(rèn)情況下,這里存儲的就是用戶登錄的 IP 地址和 sessionId。我們從源碼角度來看下。

2.源碼分析

松哥的 SpringSecurity 系列已經(jīng)寫到第 12 篇了,看了前面的文章,相信大家已經(jīng)明白用戶登錄必經(jīng)的一個過濾器就是  UsernamePasswordAuthenticationFilter,在該類的 attemptAuthentication 方法中,對請求參數(shù)做提取,在  attemptAuthentication 方法中,會調(diào)用到一個方法,就是 setDetails。

我們一起來看下 setDetails 方法:

protected void setDetails(HttpServletRequest request,   UsernamePasswordAuthenticationToken authRequest) {  authRequest.setDetails(authenticationDetailsSource.buildDetails(request)); }

UsernamePasswordAuthenticationToken 是 Authentication 的具體實現(xiàn),所以這里實際上就是在設(shè)置  details,至于 details 的值,則是通過 authenticationDetailsSource 來構(gòu)建的,我們來看下:

public class WebAuthenticationDetailsSource implements   AuthenticationDetailsSource<HttpServletRequest, WebAuthenticationDetails> {  public WebAuthenticationDetails buildDetails(HttpServletRequest context) {   return new WebAuthenticationDetails(context);  } } public class WebAuthenticationDetails implements Serializable {  private final String remoteAddress;  private final String sessionId;  public WebAuthenticationDetails(HttpServletRequest request) {   this.remoteAddress = request.getRemoteAddr();    HttpSession session = request.getSession(false);   this.sessionId = (session != null) ? session.getId() : null;  }     //省略其他方法 }

默認(rèn)通過 WebAuthenticationDetailsSource 來構(gòu)建 WebAuthenticationDetails,并將結(jié)果設(shè)置到  Authentication 的 details 屬性中去。而 WebAuthenticationDetails  中定義的屬性,大家看一下基本上就明白,這就是保存了用戶登錄地址和 sessionId。

那么看到這里,大家基本上就明白了,用戶登錄的 IP 地址實際上我們可以直接從 WebAuthenticationDetails 中獲取到。

我舉一個簡單例子,例如我們登錄成功后,可以通過如下方式隨時隨地拿到用戶 IP:

@Service public class HelloService {     public void hello() {         Authentication authentication = SecurityContextHolder.getContext().getAuthentication();         WebAuthenticationDetails details = (WebAuthenticationDetails) authentication.getDetails();         System.out.println(details);     } }

這個獲取過程之所以放在 service 來做,就是為了演示隨時隨地這個特性。然后我們在 controller  中調(diào)用該方法,當(dāng)訪問接口時,可以看到如下日志:

WebAuthenticationDetails@fffc7f0c: RemoteIpAddress: 127.0.0.1; SessionId: 303C7F254DF8B86667A2B20AA0667160

可以看到,用戶的 IP 地址和 SessionId 都給出來了。這兩個屬性在 WebAuthenticationDetails 中都有對應(yīng)的 get  方法,也可以單獨獲取屬性值。

3.定制

當(dāng)然,WebAuthenticationDetails 也可以自己定制,因為默認(rèn)它只提供了 IP 和 sessionid 兩個信息,如果我們想保存關(guān)于  Http 請求的更多信息,就可以通過自定義 WebAuthenticationDetails 來實現(xiàn)。

如果我們要定制 WebAuthenticationDetails,還要連同 WebAuthenticationDetailsSource  一起重新定義。

結(jié)合上篇文章的驗證碼登錄,我跟大家演示一個自定義 WebAuthenticationDetails 的例子。

上篇文章我們是在 MyAuthenticationProvider 類中進(jìn)行驗證碼判斷的,回顧一下上篇文章的代碼:

public class MyAuthenticationProvider extends DaoAuthenticationProvider {      @Override     protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {         HttpServletRequest req = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();         String code = req.getParameter("code");         String verify_code = (String) req.getSession().getAttribute("verify_code");         if (code == null || verify_code == null || !code.equals(verify_code)) {             throw new AuthenticationServiceException("驗證碼錯誤");         }         super.additionalAuthenticationChecks(userDetails, authentication);     } }

不過這個驗證操作,我們也可以放在自定義的 WebAuthenticationDetails 中來做,我們定義如下兩個類:

public class MyWebAuthenticationDetails extends WebAuthenticationDetails {      private boolean isPassed;      public MyWebAuthenticationDetails(HttpServletRequest req) {         super(req);         String code = req.getParameter("code");         String verify_code = (String) req.getSession().getAttribute("verify_code");         if (code != null && verify_code != null && code.equals(verify_code)) {             isPassed = true;         }     }      public boolean isPassed() {         return isPassed;     } } @Component public class MyWebAuthenticationDetailsSource implements AuthenticationDetailsSource<HttpServletRequest,MyWebAuthenticationDetails> {     @Override     public MyWebAuthenticationDetails buildDetails(HttpServletRequest context) {         return new MyWebAuthenticationDetails(context);     } }

首先我們定義 MyWebAuthenticationDetails,由于它的構(gòu)造方法中,剛好就提供了 HttpServletRequest  對象,所以我們可以直接利用該對象進(jìn)行驗證碼判斷,并將判斷結(jié)果交給 isPassed 變量保存。如果我們想擴(kuò)展屬性,只需要在  MyWebAuthenticationDetails 中再去定義更多屬性,然后從 HttpServletRequest  中提取出來設(shè)置給對應(yīng)的屬性即可,這樣,在登錄成功后就可以隨時隨地獲取這些屬性了。

最后在 MyWebAuthenticationDetailsSource 中構(gòu)造 MyWebAuthenticationDetails 并返回。

定義完成后,接下來,我們就可以直接在 MyAuthenticationProvider 中進(jìn)行調(diào)用了:

public class MyAuthenticationProvider extends DaoAuthenticationProvider {      @Override     protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {         if (!((MyWebAuthenticationDetails) authentication.getDetails()).isPassed()) {             throw new AuthenticationServiceException("驗證碼錯誤");         }         super.additionalAuthenticationChecks(userDetails, authentication);     } }

直接從 authentication 中獲取到 details 并調(diào)用 isPassed 方法,有問題就拋出異常即可。

最后的問題就是如何用自定義的 MyWebAuthenticationDetailsSource 代替系統(tǒng)默認(rèn)的  WebAuthenticationDetailsSource,很簡單,我們只需要在 SecurityConfig 中稍作定義即可:

@Autowired MyWebAuthenticationDetailsSource myWebAuthenticationDetailsSource; @Override protected void configure(HttpSecurity http) throws Exception {     http.authorizeRequests()             ...             .and()             .formLogin()             .authenticationDetailsSource(myWebAuthenticationDetailsSource)             ... }

將 MyWebAuthenticationDetailsSource 注入到 SecurityConfig 中,并在 formLogin 中配置  authenticationDetailsSource 即可成功使用我們自定義的 WebAuthenticationDetails。

這樣自定義完成后,WebAuthenticationDetails 中原有的功能依然保留,也就是我們還可以利用老辦法繼續(xù)獲取用戶 IP 以及  sessionId 等信息,如下:

@Service public class HelloService {     public void hello() {         Authentication authentication = SecurityContextHolder.getContext().getAuthentication();         MyWebAuthenticationDetails details = (MyWebAuthenticationDetails) authentication.getDetails();         System.out.println(details);     } }

這里類型強(qiáng)轉(zhuǎn)的時候,轉(zhuǎn)為 MyWebAuthenticationDetails 即可。

到此,相信大家對“如何用SpringSecurity查看登錄”有了更深的了解,不妨來實際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI