最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

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

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

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

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

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

 
@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("帳號不存在,請重新輸入");
        }
        // 自定義業(yè)務(wù)邏輯校驗
        if ("userli".equals(sysUser.getUsername())) {
            throw new BadCredentialsException("您的帳號有違規(guī)記錄,無法登錄!");
        }
        // 自定義密碼驗證
        if (!password.equals(sysUser.getPassword())){
            throw new BadCredentialsException("密碼錯誤,請重新輸入");
        }
        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;
    }
}

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

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

通過 thymeleaf 表達(dá)式獲取錯誤信息(我們選擇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="請輸入帳號">
                        </div>
                        <div class="form-group">
                            <input type="password" class="form-control" name="password" placeholder="請輸入密碼">
                        </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)用戶從登錄頁提交賬號密碼的時候,首先由

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)的登錄請求url是"/login",并且只允許POST方式的請求。

2. obtainUsername()方法參數(shù)名為"username"和"password"從HttpServletRequest中獲取用戶名和密碼(由此可以找到突破口,我們可以在自定義實現(xiàn)的loadUserByUsername方法中獲取到提交的賬號和密碼,進(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)限集合,因為目前還沒有認(rèn)證通過,所以不知道有什么權(quán)限信息,這里設(shè)置為null,然后將用戶名和密碼分別賦值給principal和credentials,同樣因為此時還未進(jìn)行身份認(rèn)證,所以setAuthenticated(false)。

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

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

前面提到用戶登錄驗證的過濾器是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這個方法來處理。

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)部實現(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); 

就是存儲到session中的錯誤信息,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對象所以需要使用${SPRING_SECURITY_LAST_EXCEPTION.message}獲取。

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

相關(guān)文章

  • 純注解版spring與mybatis的整合過程

    純注解版spring與mybatis的整合過程

    這篇文章主要介紹了純注解版spring與mybatis的整合過程,本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-06-06
  • java多線程-讀寫鎖原理

    java多線程-讀寫鎖原理

    本文主要介紹java多線程的知識,這里整理了相關(guān)資料及簡單示例代碼,有興趣的小伙伴可以參考下
    2016-09-09
  • JAVA的Random類的用法詳解

    JAVA的Random類的用法詳解

    Random類主要用來生成隨機(jī)數(shù),本文詳解介紹了Random類的用法,希望能幫到大家。
    2016-04-04
  • java實現(xiàn)雪花算法ID生成器工具類

    java實現(xiàn)雪花算法ID生成器工具類

    本文主要介紹了java實現(xiàn)雪花算法ID生成器工具類,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • Lombok如何快速構(gòu)建JavaBean與日志輸出

    Lombok如何快速構(gòu)建JavaBean與日志輸出

    這篇文章主要介紹了Lombok如何快速構(gòu)建JavaBean與日志輸出,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • 14個編寫Spring MVC控制器的實用小技巧(吐血整理)

    14個編寫Spring MVC控制器的實用小技巧(吐血整理)

    這篇文章主要介紹了14個編寫Spring MVC控制器的實用小技巧(吐血整理),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-11-11
  • Java?list如何實現(xiàn)將指定元素排在第一位

    Java?list如何實現(xiàn)將指定元素排在第一位

    這篇文章主要為大家詳細(xì)介紹了Java?list中如何實現(xiàn)將指定元素排在第一位,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2025-02-02
  • Java 如何實現(xiàn)POST(x-www-form-urlencoded)請求

    Java 如何實現(xiàn)POST(x-www-form-urlencoded)請求

    這篇文章主要介紹了Java 實現(xiàn)POST(x-www-form-urlencoded)請求,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • 關(guān)于Java中finalize析構(gòu)方法的作用詳解

    關(guān)于Java中finalize析構(gòu)方法的作用詳解

    構(gòu)造方法用于創(chuàng)建和初始化類對象,也就是說,構(gòu)造方法負(fù)責(zé)”生出“一個類對象,并可以在對象出生時進(jìn)行必要的操作,在這篇文章中會給大家簡單介紹一下析構(gòu)方法,需要的朋友可以參考下
    2023-05-05
  • Mybatis之映射實體類中不區(qū)分大小寫的解決

    Mybatis之映射實體類中不區(qū)分大小寫的解決

    這篇文章主要介紹了Mybatis之映射實體類中不區(qū)分大小寫的解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11

最新評論

色达县| 渑池县| 梅河口市| 德江县| 霍山县| 宾川县| 龙井市| 钟山县| 岑溪市| 秦安县| 河间市| 大名县| 广河县| 九寨沟县| 中方县| 新密市| 长子县| 东城区| 河源市| 会昌县| 博野县| 灵宝市| 滦南县| 嘉定区| 婺源县| 平遥县| 旺苍县| 湘潭市| 安龙县| 澎湖县| 吉隆县| 嘉义市| 安图县| 淮滨县| 临桂县| 岑巩县| 贡觉县| 宁陕县| 河南省| 密山市| 将乐县|