SpringSecurity+Redis認(rèn)證過(guò)程小結(jié)
由于今天用Security進(jìn)行權(quán)限管理的時(shí)候出現(xiàn)了一些Bug,特此發(fā)這篇博客來(lái)補(bǔ)習(xí)一下對(duì)SpringSecurity的理解
前言引入
當(dāng)今市面上用于權(quán)限管理的流行的技術(shù)棧組合是
- ssm+shrio
- SpringCloud+SpringBoot+SpringSecurity

這種搭配自然有其搭配的特點(diǎn),由于SpringBoot的自動(dòng)注入配置原理,在創(chuàng)建項(xiàng)目時(shí)就自動(dòng)注入管理SpringSecurity的過(guò)濾器容器(DelegatingFilterProxy),而這個(gè)過(guò)濾器是整個(gè)SpringSercurity的核心。掌握著SpringSercurity整個(gè)權(quán)限認(rèn)證過(guò)程,而SpringBoot很香的幫你將其自動(dòng)注入了,而用ssm
去整合Security,將會(huì)耗用大量的配置文件,不易于開(kāi)發(fā),而Security的微服務(wù)權(quán)限方案,更是能和Cloud完美融合,于是Security比Shrio更強(qiáng)大,功能更齊全。
Security的核心配置文件
核心:Class SecurityConfig extends WebSecurityConfigurerAdapter
繼承了WebSecurityConfigurerAdapter后我們關(guān)注于configure方法對(duì)于在整個(gè)安全認(rèn)證的過(guò)程進(jìn)行相關(guān)的配置,當(dāng)然在配置之前我們先簡(jiǎn)單了解一下流程

簡(jiǎn)單的看了整個(gè)權(quán)限認(rèn)證的流程,很輕易的總結(jié)得出,SpringSecurity核心的就是以下幾種配置項(xiàng)了
- 攔截器(Interceptor)
- 過(guò)濾器(Filter)
- 處理器(Handler,異常處理器,登錄成功處理器)
那我們就首先通過(guò)配置來(lái)完成認(rèn)證過(guò)程吧?。。?!
Security的認(rèn)證過(guò)程
假設(shè)我們要實(shí)現(xiàn)一下的認(rèn)證功能
1. 是登錄請(qǐng)求
- 我們需要先判斷驗(yàn)證碼是否正確(驗(yàn)證碼過(guò)濾器,通過(guò)addFilerbefore實(shí)現(xiàn)前置攔截)
- 再判斷用戶名密碼是否正確(使用自帶的用戶名密碼過(guò)濾器,UsernamePasswordAuthenticationFilter)
- 配置異常處理器(Handler)通過(guò)IO流將異常信息寫(xiě)出
關(guān)于密碼校驗(yàn)的流程:
UsernamePasswordAuthenticationFilter的密碼校驗(yàn)規(guī)則是基于AuthenticationManagerBuilder(認(rèn)證管理器)下的 UserDetailsService里的規(guī)則進(jìn)行驗(yàn)證的:
其中的核心方法:
1.public UserDetails *loadUserByUsername(String username)
通過(guò)請(qǐng)求參數(shù)的用戶名去數(shù)據(jù)庫(kù)查詢是否存在,存在則將其封裝在UserDetails里面,而驗(yàn)證過(guò)程是通過(guò)AuthenticationManagerBuilder獲取到UserDetail里的username和password來(lái)校驗(yàn)的,
這樣我們就可以通過(guò)
- 配置yaml文件設(shè)置賬號(hào)密碼
- 通過(guò)數(shù)據(jù)庫(kù)結(jié)合UserDetail來(lái)設(shè)置賬號(hào)密碼
(UserDetailsService中的方法,注意需要將UserDetailsService注入AuthenticationManagerBuilder中)
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
SysUser sysUser = sysUserService.getByUsername(username);
if (sysUser == null) {
throw new UsernameNotFoundException("用戶名或密碼不正確");
}
// 注意匹配參數(shù),前者是明文后者是暗紋
System.out.println("是否正確"+bCryptPasswordEncoder.matches("111111",sysUser.getPassword()));
return new AccountUser(sysUser.getId(), sysUser.getUsername(), sysUser.getPassword(), getUserAuthority(sysUser.getId()));
}
通過(guò)了這個(gè)驗(yàn)證后,過(guò)濾器放行,不通過(guò)就用自定義或者默認(rèn)的處理器處理
核心配置文件:
package com.markerhub.config;
import com.markerhub.security.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
LoginFailureHandler loginFailureHandler;
@Autowired
LoginSuccessHandler loginSuccessHandler;
@Autowired
CaptchaFilter captchaFilter;
@Autowired
JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
@Autowired
JwtAccessDeniedHandler jwtAccessDeniedHandler;
@Autowired
UserDetailServiceImpl userDetailService;
@Autowired
JwtLogoutSuccessHandler jwtLogoutSuccessHandler;
@Bean
JwtAuthenticationFilter jwtAuthenticationFilter() throws Exception {
JwtAuthenticationFilter jwtAuthenticationFilter = new JwtAuthenticationFilter(authenticationManager());
return jwtAuthenticationFilter;
}
@Bean
BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
private static final String[] URL_WHITELIST = {
"/login",
"/logout",
"/captcha",
"/favicon.ico",
};
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
// 登錄配置
.formLogin()
.successHandler(loginSuccessHandler)
.failureHandler(loginFailureHandler)
.and()
.logout()
.logoutSuccessHandler(jwtLogoutSuccessHandler)
// 禁用session
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
// 配置攔截規(guī)則
.and()
.authorizeRequests()
.antMatchers(URL_WHITELIST).permitAll()
.anyRequest().authenticated()
// 異常處理器
.and()
.exceptionHandling()
.authenticationEntryPoint(jwtAuthenticationEntryPoint)
.accessDeniedHandler(jwtAccessDeniedHandler)
// 配置自定義的過(guò)濾器
.and()
.addFilter(jwtAuthenticationFilter())
.addFilterBefore(captchaFilter, UsernamePasswordAuthenticationFilter.class)
;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailService);
}
}
2. 不是登錄請(qǐng)求
- 通過(guò)JwtfFilter來(lái)查看是否為登錄狀態(tài)
使用Redis整合時(shí)的注意事項(xiàng)
本質(zhì)上還是編寫(xiě)過(guò)濾器鏈:
- 在登錄請(qǐng)求前添加過(guò)濾器
- 注意驗(yàn)證碼存儲(chǔ)在redis的失效時(shí)間,如果超過(guò)失效時(shí)間將會(huì)被驗(yàn)證碼攔截器攔截下來(lái)
- 需要準(zhǔn)備一個(gè)生成驗(yàn)證碼的接口,存儲(chǔ)在Redis中
- 使用完驗(yàn)證碼需要將其刪除
// 校驗(yàn)驗(yàn)證碼邏輯
private void validate(HttpServletRequest httpServletRequest) {
String code = httpServletRequest.getParameter("code");
String key = httpServletRequest.getParameter("token");
if (StringUtils.isBlank(code) || StringUtils.isBlank(key)) {
System.out.println("驗(yàn)證碼校驗(yàn)失敗2");
throw new CaptchaException("驗(yàn)證碼錯(cuò)誤");
}
System.out.println("驗(yàn)證碼:"+redisUtil.hget(Const.CAPTCHA_KEY, key));
if (!code.equals(redisUtil.hget(Const.CAPTCHA_KEY, key))) {
System.out.println("驗(yàn)證碼校驗(yàn)失敗3");
throw new CaptchaException("驗(yàn)證碼錯(cuò)誤");
}
// 一次性使用
redisUtil.hdel(Const.CAPTCHA_KEY, key);
}
到此這篇關(guān)于SpringSecurity+Redis認(rèn)證過(guò)程總結(jié)的文章就介紹到這了,更多相關(guān)SpringSecurity Redis認(rèn)證內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring手動(dòng)生成web.xml配置文件過(guò)程詳解
這篇文章主要介紹了Spring手動(dòng)生成web.xml配置文件過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-07-07
Java?synchornized與ReentrantLock處理并發(fā)出現(xiàn)的錯(cuò)誤
synchronized機(jī)制提供了對(duì)每個(gè)對(duì)象相關(guān)的隱式監(jiān)視器鎖,并強(qiáng)制所有鎖的獲取和釋放都必須在同一個(gè)塊結(jié)構(gòu)中。當(dāng)獲取了多個(gè)鎖時(shí),必須以相反的順序釋放。即synchronized對(duì)于鎖的釋放是隱式的2023-01-01
java使用compareTo實(shí)現(xiàn)一個(gè)類的對(duì)象之間比較大小操作
這篇文章主要介紹了java使用compareTo實(shí)現(xiàn)一個(gè)類的對(duì)象之間比較大小操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-09-09
Java深入數(shù)據(jù)結(jié)構(gòu)理解掌握抽象類與接口
在類中沒(méi)有包含足夠的信息來(lái)描繪一個(gè)具體的對(duì)象,這樣的類稱為抽象類,接口是Java中最重要的概念之一,它可以被理解為一種特殊的類,不同的是接口的成員沒(méi)有執(zhí)行體,是由全局常量和公共的抽象方法所組成,本文給大家介紹Java抽象類和接口,感興趣的朋友一起看看吧2022-05-05
SpringBoot啟動(dòng)流程之引導(dǎo)上下文DefaultBootstrapContext的過(guò)程
本文詳細(xì)介紹了SpringBoot版本2.7.18中SpringApplication的run方法,引導(dǎo)注冊(cè)組件初始化器BootstrapRegistryInitializer是SpringBoot的第一個(gè)擴(kuò)展點(diǎn),負(fù)責(zé)應(yīng)用啟動(dòng)早期階段的初始化和配置,感興趣的朋友跟隨小編一起看看吧2024-11-11
JDK1.7中HashMap的死循環(huán)問(wèn)題及解決方案
這篇文章主要為大家介紹了JDK1.7中HashMap的死循環(huán)問(wèn)題及解決方案,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10

