博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java过滤器往后传参数_Spring security 自定义过滤器实现Json参数传递并兼容表单参数(实例代码)...
阅读量:5976 次
发布时间:2019-06-20

本文共 14597 字,大约阅读时间需要 48 分钟。

依赖

org.springframework.boot

spring-boot-starter-security

org.springframework.boot

spring-boot-starter-web

org.projectlombok

lombok

true

org.projectlombok

lombok

true

配置安全适配类

基本配置和配置自定义过滤器

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;

/**

* 配置拦截器保护请求

*

* @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()

//定义登录页面,未登录时,访问一个需要登录之后才能访问的接口,会自动跳转到该页面

.loginPage("/noToken")

//登录处理接口-登录时候访问的接口地址

.loginProcessingUrl("/account/login")

//定义登录时,表单中用户名的 key,默认为 username

.usernameParameter("username")

//定义登录时,表单中用户密码的 key,默认为 password

.passwordParameter("password")

// //登录成功的处理器

// .successHandler(successHandler)

// //登录失败的处理器

// .failureHandler(failureHandler)

//允许所有用户访问

.permitAll()

.and()

.logout()

.logoutUrl("/logout")

//登出成功的处理

.logoutSuccessHandler(logoutSuccessHandler)

.permitAll();

//关闭csrf跨域攻击防御

http.csrf().disable();

}

/**

* 配置权限认证服务

*

* @param auth

* @throws Exception

*/

@Override

protected void configure(AuthenticationManagerBuilder auth) throws Exception {

//权限校验-只要有一个认证通过即认为是通过的(有一个认证通过就跳出认证循环)-适用于多登录方式的系统

// 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");

//这句很关键,重用WebSecurityConfigurerAdapter配置的AuthenticationManager,不然要自己组装AuthenticationManager

filter.setAuthenticationManager(authenticationManagerBean());

return filter;

}

}

自定义过滤器

根据ContentType是否为json进行判断,如果是就从body中读取参数,进行解析,并生成权限实体,进行权限认证

否则直接使用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使用自带的过滤器获取参数

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请求使用取参数逻辑

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 帐号/邮箱/手机号

* @param password 密码/验证码

*/

private void storeAuthentication(String username, String password) {

AuthenticationStoreUtil.setUsername(username);

AuthenticationStoreUtil.setPassword(password);

}

}

其中会有body中的传参问题,所以使用ThreadLocal传递参数

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;

/**

* 登录认证之后的token

*/

private final ThreadLocal tokenStore = new ThreadLocal<>();

/**

* 需要验证用户名

*/

private final ThreadLocal usernameStore = new ThreadLocal<>();

/**

* 需要验证的密码

*/

private final ThreadLocal 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();

}

}

实现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();

}

}

其他对象见Controller 层返回值的公共包装类-避免每次都包装一次返回-InitializingBean增强至此,就可以传递Json参数了

1c6d47bc88edec90bda4e9254b998092.png

到此这篇关于Spring security 自定义过滤器实现Json参数传递并兼容表单参数的文章就介绍到这了,更多相关Spring security 自定义过滤器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

转载地址:http://boiox.baihongyu.com/

你可能感兴趣的文章
Mybatis调用Oracle中的存储过程和function
查看>>
基本安装lnmp环境
查看>>
yum源资料汇总
查看>>
7、MTC与MTV,http请求介绍
查看>>
logstash消费阿里云kafka消息
查看>>
unix 环境高级编程
查看>>
MAXIMO 快速查找实现
查看>>
Oracle——条件控制语句
查看>>
第一次作业-准备篇
查看>>
day-6 and day-7:面向对象
查看>>
CSU Double Shortest Paths 湖南省第十届省赛
查看>>
webgl像机世界
查看>>
php正则怎么使用(最全最细致)
查看>>
javascript数学运算符
查看>>
LC.155. Min Stack(非优化,两个stack 同步 + -)
查看>>
交互设计[3]--点石成金
查看>>
SCCM TP4部署Office2013
查看>>
redis主从配置<转>
查看>>
bootloader功能介绍/时钟初始化设置/串口工作原理/内存工作原理/NandFlash工作原理...
查看>>
利用console控制台调试php代码
查看>>