溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

怎么在Spring security中使用過濾器對Json參數(shù)進(jìn)行傳遞

發(fā)布時間:2021-01-26 14:02:02 來源:億速云 閱讀:383 作者:Leah 欄目:開發(fā)技術(shù)

這期內(nèi)容當(dāng)中小編將會給大家?guī)碛嘘P(guān)怎么在Spring security中使用過濾器對Json參數(shù)進(jìn)行傳遞,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

依賴

 <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>
配置安全適配類

基本配置和配置自定義過濾器

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ù)請求
   *
   * @param http
   * @throws Exception
   */
  @Override
  protected void configure(HttpSecurity http) throws Exception {
    //配置HTTP基本身份驗證//使用自定義過濾器-兼容json和表單登錄
    http.addFilterBefore(customAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
        .httpBasic()
        .and().authorizeRequests()
        //表示訪問 /setting 這個接口,需要具備 admin 這個角色
        .antMatchers("/setting").hasRole("admin")
        //表示剩余的其他接口,登錄之后就能訪問
        .anyRequest()
        .authenticated()
        .and()
        .formLogin()
        //定義登錄頁面,未登錄時,訪問一個需要登錄之后才能訪問的接口,會自動跳轉(zhuǎn)到該頁面
        .loginPage("/noToken")
        //登錄處理接口-登錄時候訪問的接口地址
        .loginProcessingUrl("/account/login")
        //定義登錄時,表單中用戶名的 key,默認(rèn)為 username
        .usernameParameter("username")
        //定義登錄時,表單中用戶密碼的 key,默認(rèn)為 password
        .passwordParameter("password")
//        //登錄成功的處理器
//        .successHandler(successHandler)
//        //登錄失敗的處理器
//        .failureHandler(failureHandler)
        //允許所有用戶訪問
        .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)限校驗-只要有一個認(rèn)證通過即認(rèn)為是通過的(有一個認(rèn)證通過就跳出認(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");
  }
 
  /**
   * 指定驗證manager
   *
   * @return
   * @throws Exception
   */
  @Override
  @Bean
  public AuthenticationManager authenticationManagerBean() throws Exception {
    return super.authenticationManagerBean();
  }
 
 
  /**
   * 注冊自定義的UsernamePasswordAuthenticationFilter
   *
   * @return
   * @throws Exception
   */
  @Bean
  public AbstractAuthenticationProcessingFilter customAuthenticationFilter() throws Exception {
    AbstractAuthenticationProcessingFilter filter = new CustomerUsernamePasswordAuthenticationFilter();
    filter.setAuthenticationSuccessHandler(successHandler);
    filter.setAuthenticationFailureHandler(failureHandler);
    //過濾器攔截的url要和登錄的url一致,否則不生效
    filter.setFilterProcessesUrl("/account/login");
 
    //這句很關(guān)鍵,重用WebSecurityConfigurerAdapter配置的AuthenticationManager,不然要自己組裝AuthenticationManager
    filter.setAuthenticationManager(authenticationManagerBean());
    return filter;
  }
}
自定義過濾器 

根據(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使用自帶的過濾器獲取參數(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請求使用取參數(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("驗證失?。簕}", e);
      authRequest = new UsernamePasswordAuthenticationToken(EMPTY, EMPTY);
    } finally {
      setDetails(request, authRequest);
      Authentication authenticate = this.getAuthenticationManager().authenticate(authRequest);
      return authenticate;
    }
  }
 
  /**
   * 保存用戶名和密碼
   *
   * @param username 帳號/郵箱/手機(jī)號
   * @param password 密碼/驗證碼
   */
  private void storeAuthentication(String username, String password) {
    AuthenticationStoreUtil.setUsername(username);
    AuthenticationStoreUtil.setPassword(password);
  }
}

 其中會有body中的傳參問題,所以使用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<>();
  /**
   * 需要驗證用戶名
   */
  private final ThreadLocal<String> usernameStore = new ThreadLocal<>();
  /**
   * 需要驗證的密碼
   */
  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 {
    //測試直接使用固定賬戶代替
    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 {
    //直接輸出的時候還是需要使用UTF-8字符集
    resp.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
    PrintWriter out = resp.getWriter();
    out.write(JSON.toJSONString(data));
    out.flush();
  }
}


上述就是小編為大家分享的怎么在Spring security中使用過濾器對Json參數(shù)進(jìn)行傳遞了,如果剛好有類似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI