Spring Security(三)

来源:https://www.cnblogs.com/yliucnblogs/archive/2019/01/15/10274928.html
-Advertisement-
Play Games

Spring Security(三) 個性化用戶認證流程 自定義登錄頁面 在配置類中指定登錄頁面和接收登錄的 url 在項目中新建登錄頁面 啟動項目時再訪問 Security 就會跳轉到你自已定義的登陸頁面讓你登錄。 深入定義(判斷是PC端還是移動端,PC端跳轉頁面,移動端響應 json) 創建一個 ...


Spring Security(三)

個性化用戶認證流程

自定義登錄頁面

在配置類中指定登錄頁面和接收登錄的 url

@Configuration
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new MyPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 啟用表單登陸
        http.formLogin()
                // 指定登錄頁面
                .loginPage("/imooc-signIn.html")
                // 登錄頁面表單提交的 action
                .loginProcessingUrl("/authentication/form")
                .and()
                // 對請求做授權
                .authorizeRequests()
                // 訪問指定url時不需要身份認證(放行)
                .antMatchers("/imooc-signIn.html").permitAll()
                // 任何請求
                .anyRequest()
                // 都需要身份認證
                .authenticated()
                .and()
                .csrf().disable();
    }
}
  • 在項目中新建登錄頁面
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登錄</title>
</head>
<body>
    <h2>標準登錄頁面</h2>
    <h3>表單登錄</h3>
    <form action="/authentication/form" method="post">
        <table>
            <tr>
                <td>用戶名:</td>
                <td><label>
                    <input type="text" name="username" />
                </label></td>
            </tr>
            <tr>
                <td>密碼:</td>
                <td><label>
                    <input type="password" name="password" />
                </label>
                </td>
            </tr>
            <tr>
                <td colspan="2">
                    <button type="submit">登錄</button>
                </td>
            </tr>
        </table>
    </form>
</body>
</html>

啟動項目時再訪問 Security 就會跳轉到你自已定義的登陸頁面讓你登錄。

在這裡插入圖片描述

  • 深入定義(判斷是PC端還是移動端,PC端跳轉頁面,移動端響應 json)

創建一個控制器,用來處理操作

@RestController
public class BrowserSecurityController {

    private static final Logger log = LoggerFactory.getLogger(BrowserSecurityController.class);

    private RequestCache requestCache = new HttpSessionRequestCache();

    private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();

    /**
     * 當需要身份驗證時跳轉到這裡處理
     */
    @RequestMapping("/authentication/require")
    @ResponseStatus(code = HttpStatus.UNAUTHORIZED)
    public Map<String, String> requireAuthentication(final HttpServletRequest request,
                                                final HttpServletResponse response) throws IOException {
        SavedRequest savedRequest = requestCache.getRequest(request, response);
        if (null != savedRequest) {
            String target = savedRequest.getRedirectUrl();
            log.info("引發跳轉的請求是 ={}", target);
            if (StringUtils.endsWithIgnoreCase(target, ".html")) {
                redirectStrategy.sendRedirect(request, response, "/imooc-signIn.html");
            }
        }
        Map<String, String> map = new HashMap<>();
        map.put("status", "401");
        map.put("msg", "error");
        map.put("content","訪問的服務需要身份認證,請引導用戶到登錄頁!" );
        return map;
    }
}
自定義登錄成功處理

要做自定義登錄成功處理需要實現一下 Security 的 AuthenticationSuccessHandler 介面

/**
 * 自定義登錄成功處理
 */
@Configuration
public class ImoocAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
    private static final Logger log = LoggerFactory.getLogger(ImoocAuthenticationSuccessHandler.class);

    private final ObjectMapper objectMapper;

    @Autowired
    public ImoocAuthenticationSuccessHandler(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }
    // 參數 Authentication 是Security的核心介面之一,封裝了用戶登錄認證信息
    // UserDetails 介面就包裝到了此介面中
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request,
                                        HttpServletResponse response,
                                        Authentication authentication) throws IOException, ServletException {
        log.info("登錄成功");
        // 響應 json 信息
        response.setContentType("application/json;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.write(objectMapper.writeValueAsString(authentication));
        out.flush();
        out.close();
    }

}
  • 啟動項目,訪問跳轉登錄頁面後,輸入正確用戶名,密碼後響應信息如下:
{
  "authorities": [
    {
      "authority": "admin"
    }
  ],
  // 包含了認證請求的信息
  "details": {
    "remoteAddress": "127.0.0.1",
    "sessionId": "1126C43793FD600CA6DC74169A38F64E"
  },
  // 這裡代表當前用戶是否經過了身份認證,boolean表示
  "authenticated": true,
  // 這裡是 我們自定義UserDetailsService介面實現類 返回的數據
  "principal": {
    "password": null,
    "username": "user",
    // 用戶許可權
    "authorities": [
      {
        "authority": "admin"
      }
    ],
    "accountNonExpired": true,
    "accountNonLocked": true,
    "credentialsNonExpired": true,
    "enabled": true
  },
  // 這裡一般代表用戶輸入的密碼,Security 做了處理,前臺不會響應
  "credentials": null,
  // 用戶名
  "name": "user"
}
自定義登錄錯誤處理

要做自定義登錄成功處理需要實現一下 Security 的 AuthenticationFailureHandler 介面

/**
 * 自定義登錄失敗處理
 */
@Configuration
public class ImoocAuthenticationFailureHandler implements AuthenticationFailureHandler {
    // 參數 AuthenticationException 是 Security 的一個抽象異常類
    @Override
    public void onAuthenticationFailure(HttpServletRequest request,
                                        HttpServletResponse response,
                                        AuthenticationException exception) throws IOException, ServletException {

    }

}
  • 啟動項目,訪問跳轉登錄頁面後,輸入錯誤用戶名,密碼後響應信息如下:
{**省略堆棧信息**"localizedMessage":"壞的憑證","message":"壞的憑證","suppressed":[]}

註意:以上兩個自定義登錄/失敗的處理,一定要在 自定義Security配置類中加入,不然不會生效!!!

加入自定義登錄成功/失敗處理

/**
 * Security 配置
 */
@Configuration
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private SecurityProperties securityProperties;

    @Autowired
    private ImoocAuthenticationSuccessHandler imoocAuthenticationSuccessHandler;

    @Autowired
    private ImoocAuthenticationFailureHandler imoocAuthenticationFailureHandler;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new MyPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        BrowserProperties browser = securityProperties.getBrowser();
        // 啟用表單登陸
        http.formLogin()
                // 指定登錄頁面
                .loginPage("/authentication/require")
                // 登錄頁面表單提交的 action
                .loginProcessingUrl("/authentication/form")
                // 引入自己定義的登錄成功處理配置類
                .successHandler(imoocAuthenticationSuccessHandler)
                // 引入自己定義的登錄失敗處理配置類
                .failureHandler(imoocAuthenticationFailureHandler)
                .and()
                // 對請求做授權
                .authorizeRequests()
                // 訪問指定url時不需要身份認證(放行)
                .antMatchers("/authentication/require",
                        browser.getLoginPage()).permitAll()
                // 任何請求
                .anyRequest()
                // 都需要身份認證
                .authenticated()
                .and()
                .csrf().disable();

    }
}

以上實現了自定義成功/失敗響應,但是要想PC/移動端通用,需要深化配置一下

  • 改造 自定義成功處理

創建一個枚舉類,用來區分 重定向,還是響應 json

public enum LoginType {

    REDIRECT, JSON;

}

讓此枚舉類成為 BrowserProperties 類的一個屬性

public class BrowserProperties {

    /**
     * 指定預設值(如果配置了用配置的頁面,沒配置用預設的。)
     */
    private String loginPage = "/imooc-signIn.html";

    /**
     * 指定登錄成功/失敗後的響應方式
     */
    private LoginType loginType = LoginType.JSON;
    
    // 省略 GET/SET/toString 方法
}

改造自定義成功處理類

/**
 * 自定義登錄成功處理
 */
@Configuration
// 讓自定義的成功處理類 繼承 Security 預設的成功處理類 SavedRequestAwareAuthenticationSuccessHandler
public class ImoocAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {

    private static final Logger log = LoggerFactory.getLogger(ImoocAuthenticationSuccessHandler.class);

    private final ObjectMapper objectMapper;

    private final SecurityProperties securityProperties;

    @Autowired
    public ImoocAuthenticationSuccessHandler(ObjectMapper om, SecurityProperties sp) {
        this.objectMapper = om;
        this.securityProperties = sp;
    }

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request,
                                        HttpServletResponse response,
                                        Authentication authentication) throws IOException, ServletException {
        log.info("登錄成功。。。");
        // 響應 json 信息
        response.setContentType("application/json;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.write(objectMapper.writeValueAsString(authentication));
        out.flush();
        out.close();
    }

}

改造自定義失敗處理類

/**
 * 自定義登錄失敗處理
 */
@Configuration
// SimpleUrlAuthenticationFailureHandler 為 Security 預設的登錄失敗處理類
public class ImoocAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {

    private static final Logger log = LoggerFactory.getLogger(ImoocAuthenticationSuccessHandler.class);

    private final ObjectMapper objectMapper;

    private final SecurityProperties securityProperties;

    @Autowired
    public ImoocAuthenticationFailureHandler(ObjectMapper om, SecurityProperties sp) {
        this.objectMapper = om;
        this.securityProperties = sp;
    }

    @Override
    public void onAuthenticationFailure(HttpServletRequest request,
                                        HttpServletResponse response,
                                        AuthenticationException exception) throws IOException, ServletException {
        log.info("登錄失敗。。。");
        // 如果配置了用 Json 響應
        if (LoginType.JSON.equals(securityProperties.getBrowser().getLoginType())) {
            // 響應狀態碼為 500
            response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
            // 響應 json 信息
            response.setContentType("application/json;charset=utf-8");
            PrintWriter out = response.getWriter();
            out.write(objectMapper.writeValueAsString(exception));
            out.flush();
            out.close();
        } else {
            // 調用父類方法
            super.onAuthenticationFailure(request, response, exception);
        }
    }
}

由於 BrowserProperties 類中的loginType屬性預設為 Json ,你可以在具體的 properties 文件中,定義一下屬性。如:

imooc.security.browser.login-type=REDIRECT

這樣可以測試一下是否配置成功。

測試圖就不貼上了,自已耐心測試一下~ :-)


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、引言 生活中有很多模板,如:簡歷模板、論文模板,PPT模板,所謂模板就是有一個特定的格式,但是可以根據自身的需求進行改動,然後實現自己的功能。這樣的好處就是可以減少自身的工作量,想想網上那麼多好的PPT模板,改吧改吧就成自己的,這是一件多酸爽的事情! 二、例子入手 現在有兩個類,分別是泡茶和泡咖 ...
  • 一直想寫關於產品設計思路或者說方案策略性的文章,一直都不好下筆,因為產品設計是一個很大很空佷泛話題,而且每個人都有自己的一套思路。基於以上情況本文只是總結個人的一套思路,供大家參考。 1.以人為本的黃金設計定律 任何產品的設計都是基於目標用戶的需求而設計,其目的是為用戶解決需求的同時並提供更高的價值 ...
  • 一、引言 電商項目中一個常見場景:提交訂單操作,提交訂單後有很多後續動作,例如:檢查訂單, 創建訂單, 減庫存,創建支付鏈接等等,這些子類的內部操作都很複雜。如果我們的客戶端程式要直接跟這些內容子系統進行耦合,那麼客戶端就得隨著子系統的改動而改動。提交訂單操作在一個電商系統中很多地方都會出現,如果每 ...
  • 以下為DI控制反轉個人理解煩請各位大牛指教~ 編寫程式時我們應當遵循抵耦合高內聚的原則(各個功能模塊互不依賴). 我們可以利用面向對象裡面介面的特性來進行DI控制反轉,讓功能模塊全部依賴介面,而不依賴具體的實現類,當程式跑起來以後通過註入的方式註入具體的實現類如以下代碼: 這樣,購物車類就實現了松耦 ...
  • 內容過程,把做工程過程較好的內容片段備份一次,如下的內容是關於 JavaBean到JSon格式的轉換例子的內容,應該對各朋友有一些用處。 User u = new User(); u.setId(1); u.setName("lizhi"); u.setAge(24); u.setHeigh("17 ...
  • 本篇主要介紹的是SpringCloud中的服務消費者(Feign)和負載均衡(Ribbon)功能的實現以及使用Feign結合Ribbon實現負載均衡。 ...
  • 1、習題 4: 更多的變數和列印 學習目標: 瞭解用戶輸入方法,明白pthon2和Python3之間的用戶輸入的區別。瞭解格式化字元串(format string)的概念,學會如何創建包含變數內容的字元串。使用專門的格式和語法把變數的內容放到字元串里,然後進行格式化的列印輸出。 1.1、用戶輸入 在 ...
  • 一、概述 只要用框架開發java,一定躲不過spring,Spring是一個輕量級的Java開源框架,存在的目的是用於構建輕量級的J2EE應用。Spring的核心是控制反轉(IOC)和麵向切麵編程(AOP)。spring有如下特點: 輕量級:應用大小和應用開支,包括應用方式 DI/IoC:提供松耦合 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...