spring security 5 (6)-认证过滤器

上一篇实现了自定义认证,但是要想彻底自定义整个认证流程,还差一个环节,即认证过滤器,它是认证的入口。本篇仍然以验证码为例,介绍自定义认证过滤器。 

自定义Authentication

第4篇讲过,自定义过滤器的主要作用就是生成未认证Authentication,作为入参给AuthenticationManager认证。而在第5篇,根据AuthenticationProvider的supports方法检查入参Authentication的不同实现类型,从而使AuthenticationManager可以支持不同的认证方式。这里就来自定义一个验证码类型的Authentication。

public class MyAuthentication extends AbstractAuthenticationToken {
	private String code;    //验证码
	public String getCode() {
		return code;
	}
	public void setCode(String code) {
		this.code = code;
	}
	//未认证Authentication构造方法
	public MyAuthentication(String code) {
		super(null);
		this.code = code;
		setAuthenticated(false);
	}
	//已认证Authentication构造方法
	public MyAuthentication(String code,Collection<? extends GrantedAuthority> authorities) {
		super(authorities);
		this.code = code;
		setAuthenticated(true);
	}
	@Override
	public Object getCredentials() {
		return null;	//纯验证码登录,不需要密码
	}
	@Override
	public Object getPrincipal() {
		return code;    //自己随便定义的Principal
	}

认证过滤器

主要作用就是根据用户登录时输入的数据,生成指定类型的Authentication, 交给AuthenticationManager认证。关于具体如何认证上一篇已经讲过,后面也会给出代码。

public class MyFilter extends AbstractAuthenticationProcessingFilter  {
	
	protected MyFilter() {
		super("/login");//拦截到登录请求时,开始执行以下方法
	}
	public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
			throws AuthenticationException {
		if (!request.getMethod().equals("POST")) {
			throw new AuthenticationServiceException("只支持POST请求");
		}
		//有了request,可以拿到任意参数,code是验证码
		String code = request.getParameter("code");
		//根据不同登录方式,生成不同类型Authentication,如这里的MyAuthentication 
		MyAuthentication authRequest = new MyAuthentication(code);
		//其他参数,可以是一个字符串,也可以任意对象。不需要像上篇配置的那么麻烦了
		authRequest.setDetails("其他参数");
		//将未认证Authentication交给AuthenticationManager去认证
		return getAuthenticationManager().authenticate(authRequest);
	}

Security配置

	public void configure(AuthenticationManagerBuilder auth) {
		auth.authenticationProvider(authenticationProvider());
	}
	//自定义认证,主要将上篇的UsernamePasswordAuthenticationFilter换成了MyAuthentication
	@Bean
	public AuthenticationProvider authenticationProvider() {
		return new AuthenticationProvider() {
			public boolean supports(Class<?> authentication) {
				//负责处理MyAuthentication类型登录认证,参考上一篇
				return (MyAuthentication.class.isAssignableFrom(authentication));
			}
			public Authentication authenticate(Authentication authentication) throws AuthenticationException {
				//轻松拿到details和principal,都是字符串,你也可以自定义任何类型
				String details =  authentication.getDetails().toString();
				String code = authentication.getPrincipal().toString();
		
				//对code进行认证,认证逻辑随意
				if (!code.equals("123")) {
					throw new BadCredentialsException("验证码错误");
				}
				//查询该code拥有的权限
				List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
				authorities.add(new SimpleGrantedAuthority("ROLE_role1"));
				// 认证通过,生成已认证的Authentication,加入请求权限 
				return new MyAuthentication(code,authorities);
			}
		};
	}
	//以下开始过滤器配置
	protected void configure(HttpSecurity http) throws Exception {
		http.authorizeRequests() 
				.antMatchers("/login/fail").anonymous()//开放登录失败接口
				.anyRequest().authenticated().and() 
			.addFilterAt(myFilter(), UsernamePasswordAuthenticationFilter.class)//配置过滤器
			.csrf().disable();
	}
	
	@Bean
	public MyFilter myFilter() throws Exception {
		MyFilter myFilter = new MyFilter();
		myFilter.setAuthenticationManager(authenticationManager());//使过滤器关联当前的authenticationManager
		myFilter.setFilterProcessesUrl("/login");//登录url,可覆盖构造方法中的url
		myFilter.setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler("/login/fail"));//登录失败url
		myFilter.setAuthenticationSuccessHandler(new SimpleUrlAuthenticationSuccessHandler("/login/success"));//登录成功url
            return myFilter;
        }

注意最后一个方法,其中配置了三个url,和第1篇formLogin配置的url似曾相识。formLogin的作用其实就是开启了默认的认证过滤器UsernamePasswordAuthenticationFilter,然后对其进行配置。这里自定义了认证过滤器以后,就不再需要formLogin了。没有formLogin,默认的认证过滤器也不再起作用。此时用户请求/login时,将被自定义的认证过滤器拦截。

注册过滤器

spring security中有过滤链的概念,收到请求以后,链中的过滤器会按指定的顺序执行。如果要往链中添加过滤器,必须放在正确的位置,确保按既定顺序执行,否则会引起混乱。可使用以下四种方法

  • .addFilterAt(filter,filter.class):将参数1的过滤器放到参数2过滤器相同的位置。这是我上面代码中用到的,将自定义认过滤器放到默认的认证过滤器UsernamePasswordAuthenticationFilter相同的位置顺序。
  • .addFilterBefore(filter,filter.class):将参数1放到参数2的前面的位置顺序。
  • .addFilterAfter(filter,filter.class):将参数1放到参数2的后面的位置顺序。由于现在UsernamePasswordAuthenticationFilter已经失效,所以不管放到它前面还是后面,效果都是一样的。
  • .addFilter(filter):只有一个参数,它必须继承系统中已注册过的过滤器,如UsernamePasswordAuthenticationFilter,以此确定它的位置顺序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值