Spring security 自定義過(guò)濾器實(shí)現(xiàn)Json參數(shù)傳遞并兼容表單參數(shù)(實(shí)例代碼)
依賴(lài)
<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>
配置安全適配類(lèi)基本配置和配置自定義過(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:枚舉類(lèi)具備線程安全性
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: <自定義用戶處理類(lèi)> * @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(); } }
登錄成功類(lèi)
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: <登錄成功處理類(lèi)> * @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: <登錄失敗操作類(lèi)> * @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); } }
登出成功類(lèi)
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); } }
返回值工具類(lèi)
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ì)象見(jiàn)Controller 層返回值的公共包裝類(lèi)-避免每次都包裝一次返回-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-06Eclipse中自動(dòng)添加注釋?zhuān)▋煞N)
本文主要介紹了Eclipse中自動(dòng)添加注釋的兩種方法。具有很好的參考價(jià)值,下面跟著小編一起來(lái)看下吧2017-02-02如何從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-03JSON.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-04JFINAL+Ajax傳參 array 數(shù)組方法 獲取request中數(shù)組操作
這篇文章主要介紹了JFINAL+Ajax傳參 array 數(shù)組方法 獲取request中數(shù)組操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-08-08Maven 多模塊父子工程的實(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-04SpringBoot配置自定義攔截器實(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