SpringSecurity+Redis認證過程小結
由于今天用Security進行權限管理的時候出現(xiàn)了一些Bug,特此發(fā)這篇博客來補習一下對SpringSecurity的理解
前言引入
當今市面上用于權限管理的流行的技術棧組合是
- ssm+shrio
- SpringCloud+SpringBoot+SpringSecurity

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

簡單的看了整個權限認證的流程,很輕易的總結得出,SpringSecurity核心的就是以下幾種配置項了
- 攔截器(Interceptor)
- 過濾器(Filter)
- 處理器(Handler,異常處理器,登錄成功處理器)
那我們就首先通過配置來完成認證過程吧!?。?!
Security的認證過程
假設我們要實現(xiàn)一下的認證功能
1. 是登錄請求
- 我們需要先判斷驗證碼是否正確(驗證碼過濾器,通過addFilerbefore實現(xiàn)前置攔截)
- 再判斷用戶名密碼是否正確(使用自帶的用戶名密碼過濾器,UsernamePasswordAuthenticationFilter)
- 配置異常處理器(Handler)通過IO流將異常信息寫出
關于密碼校驗的流程:
UsernamePasswordAuthenticationFilter的密碼校驗規(guī)則是基于AuthenticationManagerBuilder(認證管理器)下的 UserDetailsService里的規(guī)則進行驗證的:
其中的核心方法:
1.public UserDetails *loadUserByUsername(String username)
通過請求參數(shù)的用戶名去數(shù)據(jù)庫查詢是否存在,存在則將其封裝在UserDetails里面,而驗證過程是通過AuthenticationManagerBuilder獲取到UserDetail里的username和password來校驗的,
這樣我們就可以通過
- 配置yaml文件設置賬號密碼
- 通過數(shù)據(jù)庫結合UserDetail來設置賬號密碼
(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()));
}
通過了這個驗證后,過濾器放行,不通過就用自定義或者默認的處理器處理
核心配置文件:
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)
// 配置自定義的過濾器
.and()
.addFilter(jwtAuthenticationFilter())
.addFilterBefore(captchaFilter, UsernamePasswordAuthenticationFilter.class)
;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailService);
}
}
2. 不是登錄請求
- 通過JwtfFilter來查看是否為登錄狀態(tài)
使用Redis整合時的注意事項
本質(zhì)上還是編寫過濾器鏈:
- 在登錄請求前添加過濾器
- 注意驗證碼存儲在redis的失效時間,如果超過失效時間將會被驗證碼攔截器攔截下來
- 需要準備一個生成驗證碼的接口,存儲在Redis中
- 使用完驗證碼需要將其刪除
// 校驗驗證碼邏輯
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("驗證碼校驗失敗2");
throw new CaptchaException("驗證碼錯誤");
}
System.out.println("驗證碼:"+redisUtil.hget(Const.CAPTCHA_KEY, key));
if (!code.equals(redisUtil.hget(Const.CAPTCHA_KEY, key))) {
System.out.println("驗證碼校驗失敗3");
throw new CaptchaException("驗證碼錯誤");
}
// 一次性使用
redisUtil.hdel(Const.CAPTCHA_KEY, key);
}
到此這篇關于SpringSecurity+Redis認證過程總結的文章就介紹到這了,更多相關SpringSecurity Redis認證內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
IntelliJ IDEA設置JVM運行參數(shù)的操作方法
這篇文章主要介紹了IntelliJ IDEA設置JVM運行參數(shù)的操作方法,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2018-03-03
Java?在?Array?和?Set?之間進行轉(zhuǎn)換的示例
這篇文章主要介紹了Java如何在Array和Set之間進行轉(zhuǎn)換,在本文章中,我們對如何在?Java?中對Array和Set進行轉(zhuǎn)換進行一些說明和示例,需要的朋友可以參考下2023-05-05
聊聊@value注解和@ConfigurationProperties注解的使用
這篇文章主要介紹了@value注解和@ConfigurationProperties注解的使用,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09

