亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

基于Spring-Security自定義登陸錯(cuò)誤提示信息

 更新時(shí)間:2021年12月20日 10:29:09   作者:doinbb  
這篇文章主要介紹了Spring-Security自定義登陸錯(cuò)誤提示信息,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

實(shí)現(xiàn)效果如圖所示:

首先公布實(shí)現(xiàn)代碼:

一. 自定義實(shí)現(xiàn)

import.org.springframework.security.core.userdetails.UserDetailsService類

并且拋出BadCredentialsException異常,否則頁面無法獲取到錯(cuò)誤信息。

 
@Slf4j
@Service
public class MyUserDetailsServiceImpl implements UserDetailsService { 
    @Autowired
    private PasswordEncoder passwordEncoder; 
    @Autowired
    private UserService userService; 
    @Autowired
    private PermissionService permissionService; 
    private String passwordParameter = "password"; 
    @Override
    public UserDetails loadUserByUsername(String username) throws AuthenticationException {
        HttpServletRequest request = ContextHolderUtils.getRequest();
        String password = request.getParameter(passwordParameter);
        log.error("password = {}", password);
 
        SysUser sysUser = userService.getByUsername(username);
        if (null == sysUser) {
            log.error("用戶{}不存在", username);
            throw new BadCredentialsException("帳號(hào)不存在,請(qǐng)重新輸入");
        }
        // 自定義業(yè)務(wù)邏輯校驗(yàn)
        if ("userli".equals(sysUser.getUsername())) {
            throw new BadCredentialsException("您的帳號(hào)有違規(guī)記錄,無法登錄!");
        }
        // 自定義密碼驗(yàn)證
        if (!password.equals(sysUser.getPassword())){
            throw new BadCredentialsException("密碼錯(cuò)誤,請(qǐng)重新輸入");
        }
        List<SysPermission> permissionList = permissionService.findByUserId(sysUser.getId());
        List<SimpleGrantedAuthority> authorityList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(permissionList)) {
            for (SysPermission sysPermission : permissionList) {
                authorityList.add(new SimpleGrantedAuthority(sysPermission.getCode()));
            }
        }
 
        User myUser = new User(sysUser.getUsername(), passwordEncoder.encode(sysUser.getPassword()), authorityList); 
        log.info("登錄成功!用戶: {}", myUser); 
        return myUser;
    }
}

二. 實(shí)現(xiàn)自定義登陸頁面

前提是,你們已經(jīng)解決了自定義登陸頁面配置的問題,這里不做討論。

通過 thymeleaf 表達(dá)式獲取錯(cuò)誤信息(我們選擇thymeleaf模板引擎)

<p style="color: red" th:if="${param.error}"   th:text="${session.SPRING_SECURITY_LAST_EXCEPTION.message}"></p>
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>XX相親網(wǎng)</title>
    <meta name="description" content="Ela Admin - HTML5 Admin Template">
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body class="mui-content">
<div id="d1">
    <div class="first">
        <img class="hosp" th:src="@{/images/dashboard/hospital.png}"/>
        <div class="hospital">XX相親網(wǎng)</div>
    </div>
    <div class="sufee-login d-flex align-content-center flex-wrap">
        <div class="container">
            <div class="login-content">
                <div class="login-logo">
                    <h1 style="color: #385978;font-size: 24px">XX相親網(wǎng)</h1>
                    <h1 style="color: #385978;font-size: 24px">登錄</h1>
                </div>
                <div class="login-form">
                    <form th:action="@{/login}" method="post">
                        <div class="form-group">
                            <input type="text" class="form-control" name="username" placeholder="請(qǐng)輸入帳號(hào)">
                        </div>
                        <div class="form-group">
                            <input type="password" class="form-control" name="password" placeholder="請(qǐng)輸入密碼">
                        </div>
                        <div>
                            <button type="submit" class="button-style">
                                <span class="in">登錄</span>
                            </button>
                        </div>
                        <p style="color: red" th:if="${param.error}"             
                           th:text="${session.SPRING_SECURITY_LAST_EXCEPTION.message}">
                        </p>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
</body>
</html>

Spring-Security登陸表單提交過程

當(dāng)用戶從登錄頁提交賬號(hào)密碼的時(shí)候,首先由

org.springframework.security.web.authentication包下的UsernamePasswordAuthenticationFilter類attemptAuthentication()

方法來處理登陸邏輯。

 
	public Authentication attemptAuthentication(HttpServletRequest request,
			HttpServletResponse response) throws AuthenticationException {
		if (postOnly && !request.getMethod().equals("POST")) {
			throw new AuthenticationServiceException(
					"Authentication method not supported: " + request.getMethod());
		} 

		String username = obtainUsername(request);
		String password = obtainPassword(request); 
		if (username == null) {
			username = "";
		}
 
		if (password == null) {
			password = "";
		}
 
		username = username.trim(); 
		UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
				username, password); 
		// Allow subclasses to set the "details" property
		setDetails(request, authRequest); 
		return this.getAuthenticationManager().authenticate(authRequest);
	}

1. 該類內(nèi)部默認(rèn)的登錄請(qǐng)求url是"/login",并且只允許POST方式的請(qǐng)求。

2. obtainUsername()方法參數(shù)名為"username"和"password"從HttpServletRequest中獲取用戶名和密碼(由此可以找到突破口,我們可以在自定義實(shí)現(xiàn)的loadUserByUsername方法中獲取到提交的賬號(hào)和密碼,進(jìn)而檢查正則性)。

3. 通過構(gòu)造方法UsernamePasswordAuthenticationToken,將用戶名和密碼分別賦值給principal和credentials。

    public UsernamePasswordAuthenticationToken(Object principal, Object credentials) {
        super((Collection)null);
        this.principal = principal;
        this.credentials = credentials;
        this.setAuthenticated(false);
    }

super(null)調(diào)用的是父類的構(gòu)造方法,傳入的是權(quán)限集合,因?yàn)槟壳斑€沒有認(rèn)證通過,所以不知道有什么權(quán)限信息,這里設(shè)置為null,然后將用戶名和密碼分別賦值給principal和credentials,同樣因?yàn)榇藭r(shí)還未進(jìn)行身份認(rèn)證,所以setAuthenticated(false)。

到此為止,用戶提交的表單信息已加載完成,繼續(xù)往下則是校驗(yàn)表單提交的賬號(hào)和密碼是否正確。

那么異常一下是如何傳遞給前端的呢

前面提到用戶登錄驗(yàn)證的過濾器是UsernamePasswordAuthenticationFilter,它繼承自AbstractAuthenticationProcessingFilter。

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
			throws IOException, ServletException { 
		HttpServletRequest request = (HttpServletRequest) req;
		HttpServletResponse response = (HttpServletResponse) res;
 
		if (!requiresAuthentication(request, response)) {
			chain.doFilter(request, response); 
			return;
		}
 
		if (logger.isDebugEnabled()) {
			logger.debug("Request is to process authentication");
		}
 
		Authentication authResult; 
		try {
			authResult = attemptAuthentication(request, response);
			if (authResult == null) {
				// return immediately as subclass has indicated that it hasn't completed
				// authentication
				return;
			}
			sessionStrategy.onAuthentication(authResult, request, response);
		}
		catch (InternalAuthenticationServiceException failed) {
			logger.error(
					"An internal error occurred while trying to authenticate the user.",
					failed);
			unsuccessfulAuthentication(request, response, failed); 
			return;
		}
		catch (AuthenticationException failed) {
			// Authentication failed
			unsuccessfulAuthentication(request, response, failed); 
			return;
		}
 
		// Authentication success
		if (continueChainBeforeSuccessfulAuthentication) {
			chain.doFilter(request, response);
		} 
		successfulAuthentication(request, response, chain, authResult);
	}

從代碼片段中看到Spring將異常捕獲后交給了unsuccessfulAuthentication這個(gè)方法來處理。

unsuccessfulAuthentication又交給了failureHandler(AuthenticationFailureHandler)來處理,然后追蹤failureHandler

	protected void unsuccessfulAuthentication(HttpServletRequest request,
			HttpServletResponse response, AuthenticationException failed)
			throws IOException, ServletException {
		SecurityContextHolder.clearContext();
 
		if (logger.isDebugEnabled()) {
			logger.debug("Authentication request failed: " + failed.toString(), failed);
			logger.debug("Updated SecurityContextHolder to contain null Authentication");
			logger.debug("Delegating to authentication failure handler " + failureHandler);
		}
 
		rememberMeServices.loginFail(request, response); 
		failureHandler.onAuthenticationFailure(request, response, failed);
	}

Ctrl + 左鍵 追蹤failureHandler引用的類是,SimpleUrlAuthenticationFailureHandler。

	private AuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
	private AuthenticationFailureHandler failureHandler = new SimpleUrlAuthenticationFailureHandler();

找到SimpleUrlAuthenticationFailureHandler類中的,onAuthenticationFailure()方法。

	public void onAuthenticationFailure(HttpServletRequest request,
			HttpServletResponse response, AuthenticationException exception)
			throws IOException, ServletException {
 
		if (defaultFailureUrl == null) {
			logger.debug("No failure URL set, sending 401 Unauthorized error");
 
			response.sendError(HttpServletResponse.SC_UNAUTHORIZED,
					"Authentication Failed: " + exception.getMessage());
		}
		else {
			saveException(request, exception);
 
			if (forwardToDestination) {
				logger.debug("Forwarding to " + defaultFailureUrl);
 
				request.getRequestDispatcher(defaultFailureUrl)
						.forward(request, response);
			}
			else {
				logger.debug("Redirecting to " + defaultFailureUrl);
				redirectStrategy.sendRedirect(request, response, defaultFailureUrl);
			}
		}
	}

追蹤到saveException(request, exception)的內(nèi)部實(shí)現(xiàn)。

	protected final void saveException(HttpServletRequest request,
			AuthenticationException exception) {
		if (forwardToDestination) {
			request.setAttribute(WebAttributes.AUTHENTICATION_EXCEPTION, exception);
		}
		else {
			HttpSession session = request.getSession(false);
 
			if (session != null || allowSessionCreation) {
				request.getSession().setAttribute(WebAttributes.AUTHENTICATION_EXCEPTION,
						exception);
			}
		}
	}

此處的

request.getSession().setAttribute(WebAttributes.AUTHENTICATION_EXCEPTION, exception); 

就是存儲(chǔ)到session中的錯(cuò)誤信息,key就是

public static final String AUTHENTICATION_EXCEPTION =
"SPRING_SECURITY_LAST_EXCEPTION";

因此我們通過thymeleaf模板引擎的表達(dá)式可獲得session的信息。

獲取方式

<p style="color: red" th:if="${param.error}" 
th:text="${session.SPRING_SECURITY_LAST_EXCEPTION.message}">
</p>

需要注意:saveException保存的是Session對(duì)象所以需要使用${SPRING_SECURITY_LAST_EXCEPTION.message}獲取。

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 解決SpringBoot跨域的三種方式

    解決SpringBoot跨域的三種方式

    前后端分離是目前的趨勢,解決跨域問題也是老生常談的話題了,我們了解一下什么是域和跨域。域:協(xié)議 + 域名 + 端口;三者完全相同則為同域,反之有其一不同均為不同域??缬蛘?qǐng)求:當(dāng)前【發(fā)起請(qǐng)求】的域和【請(qǐng)求指向】的域?qū)儆诓煌驎r(shí),該次請(qǐng)求稱之為跨域請(qǐng)求
    2021-06-06
  • 深入淺出分析Java抽象類和接口【功能,定義,用法,區(qū)別】

    深入淺出分析Java抽象類和接口【功能,定義,用法,區(qū)別】

    這篇文章主要介紹了Java抽象類和接口,結(jié)合實(shí)例形式深入淺出的分析了java抽象類與接口的功能功能,定義,用法及區(qū)別,需要的朋友可以參考下
    2017-08-08
  • Java?常量池詳解之class文件常量池?和class運(yùn)行時(shí)常量池

    Java?常量池詳解之class文件常量池?和class運(yùn)行時(shí)常量池

    這篇文章主要介紹了Java?常量池詳解之class文件常量池?和class運(yùn)行時(shí)常量池,常量池主要存放兩大類常量:字面量,符號(hào)引用,本文結(jié)合示例代碼對(duì)java class常量池相關(guān)知識(shí)介紹的非常詳細(xì),需要的朋友可以參考下
    2022-12-12
  • Java索引越界異常Exception java.lang.IndexOutOfBoundsException的解決

    Java索引越界異常Exception java.lang.IndexOutOfBoundsException

    本文主要介紹了Java索引越界異常Exception java.lang.IndexOutOfBoundsException的解決,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06
  • Java五子棋簡單實(shí)現(xiàn)代碼舉例

    Java五子棋簡單實(shí)現(xiàn)代碼舉例

    Java五子棋游戲是一種經(jīng)典的兩人對(duì)戰(zhàn)棋類游戲,它基于簡單的規(guī)則,即任何一方的棋子在棋盤上形成連續(xù)的五個(gè),無論是橫、豎還是斜線,都將獲勝,這篇文章主要介紹了Java五子棋實(shí)現(xiàn)的相關(guān)資料,需要的朋友可以參考下
    2024-10-10
  • 基于FlashPaper實(shí)現(xiàn)JSP在線閱讀代碼示例

    基于FlashPaper實(shí)現(xiàn)JSP在線閱讀代碼示例

    這篇文章主要介紹了基于FlashPaper實(shí)現(xiàn)JSP在線閱讀代碼示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-10-10
  • Google Kaptcha 框架實(shí)現(xiàn)登錄驗(yàn)證碼功能(SSM 和 SpringBoot)

    Google Kaptcha 框架實(shí)現(xiàn)登錄驗(yàn)證碼功能(SSM 和 SpringBoot)

    這篇文章主要介紹了Google Kaptcha 實(shí)現(xiàn)登錄驗(yàn)證碼(SSM 和 SpringBoot)功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2018-12-12
  • SpringBoot項(xiàng)目整合jasypt實(shí)現(xiàn)過程詳解

    SpringBoot項(xiàng)目整合jasypt實(shí)現(xiàn)過程詳解

    這篇文章主要介紹了SpringBoot項(xiàng)目整合jasypt實(shí)現(xiàn)過程詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-08-08
  • Java super關(guān)鍵字的用法詳解

    Java super關(guān)鍵字的用法詳解

    在JAVA類中使用super來引用父類的成分,用this來引用當(dāng)前對(duì)象,如果一個(gè)類從另外一個(gè)類繼承,我們new這個(gè)子類的實(shí)例對(duì)象的時(shí)候,這個(gè)子類對(duì)象里面會(huì)有一個(gè)父類對(duì)象。怎么引用里面的父類對(duì)象呢?用super來引用,this指當(dāng)前對(duì)象的引用,super是當(dāng)前對(duì)象里面的父對(duì)象的引用
    2021-11-11
  • Springboot報(bào)錯(cuò)java.lang.NullPointerException: null問題

    Springboot報(bào)錯(cuò)java.lang.NullPointerException: null問題

    這篇文章主要介紹了Springboot報(bào)錯(cuò)java.lang.NullPointerException: null問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-11-11

最新評(píng)論