package com.github.liuweijw.system.auth.component.ajax;

import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

import com.github.liuweijw.system.api.UserFeignApi;
import com.github.liuweijw.system.api.model.AuthUser;
import com.github.liuweijw.system.auth.service.UserDetailsImpl;

/**
 * 自定义参数验证 <br/>
 * 可以在自定义登录界面添加登录时需要的参数,如多个验证码等、可以修改默认登录名称和密码的参数名 整体流程:<br/>
 * 1.用户登录时,先经过自定义的passcard_filter过滤器,该过滤器继承了AbstractAuthenticationProcessingFilter,并且绑定了登录失败和成功时需要的处理器(跳转页面使用)<br/>
 * 2.执行attemptAuthentication方法,可以通过request获取登录页面传递的参数,实现自己的逻辑,并且把对应参数set到AbstractAuthenticationToken的实现类中<br/>
 * 3.验证逻辑走完后,调用 this.getAuthenticationManager().authenticate(token);方法,执行AuthenticationProvider的实现类的supports方法<br/>
 * 4.如果返回true则继续执行authenticate方法<br/>
 * 5.在authenticate方法中,首先可以根据用户名获取到用户信息,再者可以拿自定义参数和用户信息做逻辑验证,如密码的验证<br/>
 * 6.自定义验证通过以后,获取用户权限set到User中,用于springSecurity做权限验证<br/>
 * 7.this.getAuthenticationManager().authenticate(token)方法执行完后,会返回Authentication,如果不为空,则说明验证通过<br/>
 * 8.验证通过后,可实现自定义逻辑操作,如记录cookie信息<br/>
 * 9.attemptAuthentication方法执行完成后,由springSecuriy来进行对应权限验证,成功于否会跳转到相对应处理器设置的界面。<br/>
 * 
 * @author liuweijw
 */
public class AjaxAuthenticationProvider implements AuthenticationProvider {

	private UserFeignApi	userFeignApi;

	@Override
	public Authentication authenticate(Authentication authentication) throws AuthenticationException {
		AjaxAuthenticationToken ajaxAuthenticationToken = (AjaxAuthenticationToken) authentication;
		AuthUser user = userFeignApi.findUserByMobile((String) ajaxAuthenticationToken.getPrincipal());

		if (null == user)
			throw new UsernameNotFoundException("登录账户[" + ajaxAuthenticationToken.getPrincipal() + "]不存在");

		UserDetailsImpl userDetails = buildUserDeatils(user);

		if (null == userDetails)
			throw new InternalAuthenticationServiceException("登录用户[" + ajaxAuthenticationToken.getPrincipal() + "]不存在!");

		AjaxAuthenticationToken authenticationToken = new AjaxAuthenticationToken(userDetails, userDetails.getAuthorities());
		authenticationToken.setDetails(ajaxAuthenticationToken.getDetails());
		return authenticationToken;
	}

	private UserDetailsImpl buildUserDeatils(AuthUser authUser) {
		return new UserDetailsImpl(authUser);
	}

	@Override
	public boolean supports(Class<?> authentication) {
		return AjaxAuthenticationToken.class.isAssignableFrom(authentication);
	}

	public UserFeignApi getUserFeignApi() {
		return userFeignApi;
	}

	public void setUserFeignApi(UserFeignApi userFeignApi) {
		this.userFeignApi = userFeignApi;
	}

}