在第二章节,咱们主要学习了Security的自定义认证的实现和认证的流程,同时也存在一些问题,好比咱们想在用户认证成功或失败后记录日志等相关操做,咱们怎么办呢?别担忧,Security已经为咱们想好了,咱们只须要实现其提供的接口并配置便可。html
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
经过名字你们应该能够猜出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的含义是我是第一次通过认证的。
而这里抛出的异常信息“坏的凭证”则会被咱们的失败处理器所捕获,这就是异常信息捕获的所有过程。
第二节咱们详细的讲解了异常信息的捕获流程,可是在咱们的实际业务需求中,异常信息可能不是“坏的凭证”这样的字符串,若是我想自定义信息,怎么办呢?也很简单,请看代码:
我将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登陆,效果以下。