Spring Security修炼手册(三)————Security个性化认证流程

    在第二章节,咱们主要学习了Security的自定义认证的实现和认证的流程,同时也存在一些问题,好比咱们想在用户认证成功或失败后记录日志等相关操做,咱们怎么办呢?别担忧,Security已经为咱们想好了,咱们只须要实现其提供的接口并配置便可。html

1、 自定义登陆成功处理  

    AuthenticationSuccessHandle是Security提供的认证成功处理器接口,代码以下:前端

    如今咱们具体实现如下,好比咱们在用户认证成功后,打印一段某某用户在什么时间登陆成功的日志,并返回给前端页面当前用户的认证信息:java

import java.io.IOException;
import java.util.Date;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

import com.fasterxml.jackson.databind.ObjectMapper;

@Component
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
		
	private Logger logger = LoggerFactory.getLogger(getClass());
	@Autowired
	private ObjectMapper objectMapper;
	@Override
	public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
			Authentication authentication) throws IOException, ServletException {
		// TODO Auto-generated method stub
		logger.info(authentication.getName()+"在"+new Date()+"登陆成功");
		response.setContentType("application/json;charset=UTF-8");
		response.getWriter().write(objectMapper.writeValueAsString(authentication));

	}

}

    而后咱们须要将认证成功处理器在SecurityConfig中配置一下:web

启动项目,再次登陆,web界面显示以下:spring

     咱们能够看到Authentication中有当前用户的权限、Session、名字等等信息,Authentication就是认证成功后Security为咱们提供的一个封装,里面具体都有什么属性,感兴趣的朋友能够具体去看这个接口,这里不作详述。数据库

        后台Log输出以下:json

2、 自定义认证失败处理  

        经过名字你们应该能够猜出Security提供的失败处理器的名字叫作:AuthenticationFailureHandler,app

这个处理器和成功处理器仍是有区别的,成功处理器方法中最后一个参数是封装好的用户认证信息,而失败处理器最后一个参数是在UserDetailServer中所捕获到的异常信息。能够看下我实现的逻辑:打印抛出的异常信息。框架

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;

@Component
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {

	private Logger logger = LoggerFactory.getLogger(getClass());
	/* (non-Javadoc)
	 * @see org.springframework.security.web.authentication.AuthenticationFailureHandler#onAuthenticationFailure(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, org.springframework.security.core.AuthenticationException)
	 */
	@Override
	public void onAuthenticationFailure(HttpServletRequest arg0, HttpServletResponse response, AuthenticationException authentication)
			throws IOException, ServletException {
		
		logger.info(authentication.getMessage()+"---登陆失败");
		response.setHeader("content-type","text/html;charset=UTF-8");
		response.getWriter().println("<script>alert('"+ authentication.getMessage()+"');</script>");

	}

}

一样的在SecurityConfig中配置失败处理器,再次登陆:ide

    能够看到打印出的异常信息为“坏的凭证”,实际上这个是Security中默认的异常信息,咱们跑一遍源码,来看一看Security是怎么对比咱们在表单输入的信息与UserDetailServer中(数据库)的对比,以及异常的处理的。

    任意输入用户名,密码,点击登陆,咱们仍是先来到了UsernamePasswordAuthenticationFilter中。

咱们继续往下走,一直走到咱们的UserDetailServer的实现中。

    走到User的时候咱们直接走进去,进入到DaoAuthenticationProvider,在这里会对User进行初步的检查,咱们看右上角的堆栈信息,能够看到loadedUser中我画红框值为true的属性,实际上这几个是框架默认填充的值,这由于咱们只调用了三个参数的构造器,若是咱们调用七个参数的构造器,就能够根据咱们本身的业务逻辑去进行true或false的判断,抛出相应的异常信息。

当咱们继续走,下面就开始对User进行用户名,密码,是否可用等等各类检查,若是发现出现问题,则抛出异常信息。

因为我填写的密码是错误的,因此在检查过程当中,抛出如下异常“坏的凭证”,认证是是失败的,那个false的含义是我是第一次通过认证的。

而这里抛出的异常信息“坏的凭证”则会被咱们的失败处理器所捕获,这就是异常信息捕获的所有过程。

3、自定义异常信息

    第二节咱们详细的讲解了异常信息的捕获流程,可是在咱们的实际业务需求中,异常信息可能不是“坏的凭证”这样的字符串,若是我想自定义信息,怎么办呢?也很简单,请看代码:

    我将UserDetailServer稍做修改。

import org.springframework.security.core.authority.AuthorityUtils;
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.stereotype.Component;

@Component
public class MyUserDetailsServer implements UserDetailsService {

	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		// TODO Auto-generated method stub
		if("admin".equals(username)){
			
			throw new RuntimeException("admin禁止登陆");
		}
		return new User(username, "$2a$10$ofPkBDUezOJp6Sik63Q/0.QlU8a1itEyzldjSXqfn2nDPqXjN0Ljm", AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
	}

}

我这里只是举一个例子,具体大家的业务需求是怎样的,本身实现就好。重启项目,使用admin登陆,效果以下。

相关文章
相关标签/搜索