Spring security 自定義過(guò)濾器實(shí)現(xiàn)Json參數(shù)傳遞并兼容表單參數(shù)(實(shí)例代碼)
依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
配置安全適配類基本配置和配置自定義過(guò)濾器
package com.study.auth.config.core;
import com.study.auth.config.core.authentication.AccountAuthenticationProvider;
import com.study.auth.config.core.authentication.MailAuthenticationProvider;
import com.study.auth.config.core.authentication.PhoneAuthenticationProvider;
import com.study.auth.config.core.filter.CustomerUsernamePasswordAuthenticationFilter;
import com.study.auth.config.core.handler.CustomerAuthenticationFailureHandler;
import com.study.auth.config.core.handler.CustomerAuthenticationSuccessHandler;
import com.study.auth.config.core.handler.CustomerLogoutSuccessHandler;
import com.study.auth.config.core.observer.CustomerUserDetailsService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
/**
* @Package: com.study.auth.config
* @Description: <>
* @Author: milla
* @CreateDate: 2020/09/04 11:27
* @UpdateUser: milla
* @UpdateDate: 2020/09/04 11:27
* @UpdateRemark: <>
* @Version: 1.0
*/
@Slf4j
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private AccountAuthenticationProvider provider;
@Autowired
private MailAuthenticationProvider mailProvider;
@Autowired
private PhoneAuthenticationProvider phoneProvider;
@Autowired
private CustomerUserDetailsService userDetailsService;
@Autowired
private CustomerAuthenticationSuccessHandler successHandler;
@Autowired
private CustomerAuthenticationFailureHandler failureHandler;
@Autowired
private CustomerLogoutSuccessHandler logoutSuccessHandler;
/**
* 配置攔截器保護(hù)請(qǐng)求
*
* @param http
* @throws Exception
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
//配置HTTP基本身份驗(yàn)證//使用自定義過(guò)濾器-兼容json和表單登錄
http.addFilterBefore(customAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
.httpBasic()
.and().authorizeRequests()
//表示訪問(wèn) /setting 這個(gè)接口,需要具備 admin 這個(gè)角色
.antMatchers("/setting").hasRole("admin")
//表示剩余的其他接口,登錄之后就能訪問(wèn)
.anyRequest()
.authenticated()
.and()
.formLogin()
//定義登錄頁(yè)面,未登錄時(shí),訪問(wèn)一個(gè)需要登錄之后才能訪問(wèn)的接口,會(huì)自動(dòng)跳轉(zhuǎn)到該頁(yè)面
.loginPage("/noToken")
//登錄處理接口-登錄時(shí)候訪問(wèn)的接口地址
.loginProcessingUrl("/account/login")
//定義登錄時(shí),表單中用戶名的 key,默認(rèn)為 username
.usernameParameter("username")
//定義登錄時(shí),表單中用戶密碼的 key,默認(rèn)為 password
.passwordParameter("password")
// //登錄成功的處理器
// .successHandler(successHandler)
// //登錄失敗的處理器
// .failureHandler(failureHandler)
//允許所有用戶訪問(wèn)
.permitAll()
.and()
.logout()
.logoutUrl("/logout")
//登出成功的處理
.logoutSuccessHandler(logoutSuccessHandler)
.permitAll();
//關(guān)閉csrf跨域攻擊防御
http.csrf().disable();
}
/**
* 配置權(quán)限認(rèn)證服務(wù)
*
* @param auth
* @throws Exception
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//權(quán)限校驗(yàn)-只要有一個(gè)認(rèn)證通過(guò)即認(rèn)為是通過(guò)的(有一個(gè)認(rèn)證通過(guò)就跳出認(rèn)證循環(huán))-適用于多登錄方式的系統(tǒng)
// auth.authenticationProvider(provider);
// auth.authenticationProvider(mailProvider);
// auth.authenticationProvider(phoneProvider);
//直接使用userDetailsService
auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
}
/**
* 配置Spring Security的Filter鏈
*
* @param web
* @throws Exception
*/
@Override
public void configure(WebSecurity web) throws Exception {
//忽略攔截的接口
web.ignoring().antMatchers("/noToken");
}
/**
* 指定驗(yàn)證manager
*
* @return
* @throws Exception
*/
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
/**
* 注冊(cè)自定義的UsernamePasswordAuthenticationFilter
*
* @return
* @throws Exception
*/
@Bean
public AbstractAuthenticationProcessingFilter customAuthenticationFilter() throws Exception {
AbstractAuthenticationProcessingFilter filter = new CustomerUsernamePasswordAuthenticationFilter();
filter.setAuthenticationSuccessHandler(successHandler);
filter.setAuthenticationFailureHandler(failureHandler);
//過(guò)濾器攔截的url要和登錄的url一致,否則不生效
filter.setFilterProcessesUrl("/account/login");
//這句很關(guān)鍵,重用WebSecurityConfigurerAdapter配置的AuthenticationManager,不然要自己組裝AuthenticationManager
filter.setAuthenticationManager(authenticationManagerBean());
return filter;
}
}
自定義過(guò)濾器根據(jù)ContentType是否為json進(jìn)行判斷,如果是就從body中讀取參數(shù),進(jìn)行解析,并生成權(quán)限實(shí)體,進(jìn)行權(quán)限認(rèn)證
否則直接使用UsernamePasswordAuthenticationFilter中的方法
package com.study.auth.config.core.filter;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.study.auth.config.core.util.AuthenticationStoreUtil;
import com.study.auth.entity.bo.LoginBO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
/**
* @Package: com.study.auth.config.core.filter
* @Description: <>
* @Author: milla
* @CreateDate: 2020/09/11 16:04
* @UpdateUser: milla
* @UpdateDate: 2020/09/11 16:04
* @UpdateRemark: <>
* @Version: 1.0
*/
@Slf4j
public class CustomerUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
/**
* 空字符串
*/
private final String EMPTY = "";
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
//如果不是json使用自帶的過(guò)濾器獲取參數(shù)
if (!request.getContentType().equals(MediaType.APPLICATION_JSON_UTF8_VALUE) && !request.getContentType().equals(MediaType.APPLICATION_JSON_VALUE)) {
String username = this.obtainUsername(request);
String password = this.obtainPassword(request);
storeAuthentication(username, password);
Authentication authentication = super.attemptAuthentication(request, response);
return authentication;
}
//如果是json請(qǐng)求使用取參數(shù)邏輯
ObjectMapper mapper = new ObjectMapper();
UsernamePasswordAuthenticationToken authRequest = null;
try (InputStream is = request.getInputStream()) {
LoginBO account = mapper.readValue(is, LoginBO.class);
storeAuthentication(account.getUsername(), account.getPassword());
authRequest = new UsernamePasswordAuthenticationToken(account.getUsername(), account.getPassword());
} catch (IOException e) {
log.error("驗(yàn)證失敗:{}", e);
authRequest = new UsernamePasswordAuthenticationToken(EMPTY, EMPTY);
} finally {
setDetails(request, authRequest);
Authentication authenticate = this.getAuthenticationManager().authenticate(authRequest);
return authenticate;
}
}
/**
* 保存用戶名和密碼
*
* @param username 帳號(hào)/郵箱/手機(jī)號(hào)
* @param password 密碼/驗(yàn)證碼
*/
private void storeAuthentication(String username, String password) {
AuthenticationStoreUtil.setUsername(username);
AuthenticationStoreUtil.setPassword(password);
}
}
其中會(huì)有body中的傳參問(wèn)題,所以使用ThreadLocal傳遞參數(shù)
PS:枚舉類具備線程安全性
package com.study.auth.config.core.util;
/**
* @Package: com.study.auth.config.core.util
* @Description: <使用枚舉可以保證線程安全>
* @Author: milla
* @CreateDate: 2020/09/11 17:48
* @UpdateUser: milla
* @UpdateDate: 2020/09/11 17:48
* @UpdateRemark: <>
* @Version: 1.0
*/
public enum AuthenticationStoreUtil {
AUTHENTICATION;
/**
* 登錄認(rèn)證之后的token
*/
private final ThreadLocal<String> tokenStore = new ThreadLocal<>();
/**
* 需要驗(yàn)證用戶名
*/
private final ThreadLocal<String> usernameStore = new ThreadLocal<>();
/**
* 需要驗(yàn)證的密碼
*/
private final ThreadLocal<String> passwordStore = new ThreadLocal<>();
public static String getUsername() {
return AUTHENTICATION.usernameStore.get();
}
public static void setUsername(String username) {
AUTHENTICATION.usernameStore.set(username);
}
public static String getPassword() {
return AUTHENTICATION.passwordStore.get();
}
public static void setPassword(String password) {
AUTHENTICATION.passwordStore.set(password);
}
public static String getToken() {
return AUTHENTICATION.tokenStore.get();
}
public static void setToken(String token) {
AUTHENTICATION.tokenStore.set(token);
}
public static void clear() {
AUTHENTICATION.tokenStore.remove();
AUTHENTICATION.passwordStore.remove();
AUTHENTICATION.usernameStore.remove();
}
}
實(shí)現(xiàn)UserDetailsService接口
package com.study.auth.config.core.observer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
/**
* @Package: com.study.auth.config.core
* @Description: <自定義用戶處理類>
* @Author: milla
* @CreateDate: 2020/09/04 13:53
* @UpdateUser: milla
* @UpdateDate: 2020/09/04 13:53
* @UpdateRemark: <>
* @Version: 1.0
*/
@Slf4j
@Component
public class CustomerUserDetailsService implements UserDetailsService {
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//測(cè)試直接使用固定賬戶代替
return User.withUsername("admin").password(passwordEncoder.encode("admin")).roles("admin", "user").build();
}
}
登錄成功類
package com.study.auth.config.core.handler;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @Package: com.study.auth.config.core.handler
* @Description: <登錄成功處理類>
* @Author: milla
* @CreateDate: 2020/09/08 17:39
* @UpdateUser: milla
* @UpdateDate: 2020/09/08 17:39
* @UpdateRemark: <>
* @Version: 1.0
*/
@Component
public class CustomerAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
HttpServletResponseUtil.loginSuccess(response);
}
}
登錄失敗
package com.study.auth.config.core.handler;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @Package: com.study.auth.config.core.handler
* @Description: <登錄失敗操作類>
* @Author: milla
* @CreateDate: 2020/09/08 17:42
* @UpdateUser: milla
* @UpdateDate: 2020/09/08 17:42
* @UpdateRemark: <>
* @Version: 1.0
*/
@Component
public class CustomerAuthenticationFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
HttpServletResponseUtil.loginFailure(response, exception);
}
}
登出成功類
package com.study.auth.config.core.handler;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @Package: com.study.auth.config.core.handler
* @Description: <登出成功>
* @Author: milla
* @CreateDate: 2020/09/08 17:44
* @UpdateUser: milla
* @UpdateDate: 2020/09/08 17:44
* @UpdateRemark: <>
* @Version: 1.0
*/
@Component
public class CustomerLogoutSuccessHandler implements LogoutSuccessHandler {
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
HttpServletResponseUtil.logoutSuccess(response);
}
}
返回值工具類
package com.study.auth.config.core.handler;
import com.alibaba.fastjson.JSON;
import com.study.auth.comm.ResponseData;
import com.study.auth.constant.CommonConstant;
import org.springframework.http.MediaType;
import org.springframework.security.core.AuthenticationException;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* @Package: com.study.auth.config.core.handler
* @Description: <>
* @Author: milla
* @CreateDate: 2020/09/08 17:45
* @UpdateUser: milla
* @UpdateDate: 2020/09/08 17:45
* @UpdateRemark: <>
* @Version: 1.0
*/
public final class HttpServletResponseUtil {
public static void loginSuccess(HttpServletResponse resp) throws IOException {
ResponseData success = ResponseData.success();
success.setMsg("login success");
response(resp, success);
}
public static void logoutSuccess(HttpServletResponse resp) throws IOException {
ResponseData success = ResponseData.success();
success.setMsg("logout success");
response(resp, success);
}
public static void loginFailure(HttpServletResponse resp, AuthenticationException exception) throws IOException {
ResponseData failure = ResponseData.error(CommonConstant.EX_RUN_TIME_EXCEPTION, exception.getMessage());
response(resp, failure);
}
private static void response(HttpServletResponse resp, ResponseData data) throws IOException {
//直接輸出的時(shí)候還是需要使用UTF-8字符集
resp.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
PrintWriter out = resp.getWriter();
out.write(JSON.toJSONString(data));
out.flush();
}
}
其他對(duì)象見Controller 層返回值的公共包裝類-避免每次都包裝一次返回-InitializingBean增強(qiáng)
至此,就可以傳遞Json參數(shù)了

到此這篇關(guān)于Spring security 自定義過(guò)濾器實(shí)現(xiàn)Json參數(shù)傳遞并兼容表單參數(shù)的文章就介紹到這了,更多相關(guān)Spring security 自定義過(guò)濾器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 全面解析Spring Security 過(guò)濾器鏈的機(jī)制和特性
- Spring Security常用過(guò)濾器實(shí)例解析
- Spring Security CsrfFilter過(guò)濾器用法實(shí)例
- SpringSecurity學(xué)習(xí)之自定義過(guò)濾器的實(shí)現(xiàn)代碼
- SpringSecurity實(shí)現(xiàn)圖形驗(yàn)證碼功能的實(shí)例代碼
- SpringBoot結(jié)合SpringSecurity實(shí)現(xiàn)圖形驗(yàn)證碼功能
- Spring Security基于過(guò)濾器實(shí)現(xiàn)圖形驗(yàn)證碼功能
相關(guān)文章
淺談java object對(duì)象在heap中的結(jié)構(gòu)
本文主要介紹了淺談java object對(duì)象在heap中的結(jié)構(gòu),感興趣的同學(xué),可以參考下。2021-06-06
如何從eureka獲取服務(wù)的ip和端口號(hào)進(jìn)行Http的調(diào)用
這篇文章主要介紹了如何從eureka獲取服務(wù)的ip和端口號(hào)進(jìn)行Http的調(diào)用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03
JSON.toJSONString()方法在Java中的使用方法及應(yīng)用場(chǎng)景
這篇文章主要給大家介紹了關(guān)于JSON.toJSONString()方法在Java中的使用方法及應(yīng)用場(chǎng)景,JSON.toJSONString是將對(duì)象轉(zhuǎn)化為Json字符串,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-04-04
JFINAL+Ajax傳參 array 數(shù)組方法 獲取request中數(shù)組操作
這篇文章主要介紹了JFINAL+Ajax傳參 array 數(shù)組方法 獲取request中數(shù)組操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-08-08
Maven 多模塊父子工程的實(shí)現(xiàn)(含Spring Boot示例)
這篇文章主要介紹了Maven 多模塊父子工程的實(shí)現(xiàn)(含Spring Boot示例),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04
SpringBoot配置自定義攔截器實(shí)現(xiàn)過(guò)程詳解
在系統(tǒng)中經(jīng)常需要在處理用戶請(qǐng)求之前和之后執(zhí)行一些行為,例如檢測(cè)用戶的權(quán)限,或者將請(qǐng)求的信息記錄到日志中,即平時(shí)所說(shuō)的"權(quán)限檢測(cè)"及"日志記錄",下面這篇文章主要給大家介紹了關(guān)于在SpringBoot項(xiàng)目中整合攔截器的相關(guān)資料,需要的朋友可以參考下2022-10-10

