目录
一、Spring Security基本原理
简单来说Spring Security就是一个过滤器链,对于蓝色的过滤器我们可以修改和添加,其他颜色的过滤器链是默认的无法修改
断点验证
具体停留就不截图了,在访问的时候,例如请求路径是/user,首先它进入的是FilterSecurityInterceptor,验证发现没有填写用户信息和名字,就会抛出异常被ExceptionTranslationFilter捕获进入到beforeInvocation()方法中
接着前台就会进入到登陆界面,输入用户和密码,点击登陆之后它会向后台发送/login的请求并且进入到
UsernamePasswordAuthenticationFilter类中进行验证用户和密码。验证完毕之后进入到try方法
执行我们requestmapping
最后将信息返回给前台
二、security的简单实现
创建MyUserDetailsService类继承UserDetailsService
@Component
public class MyUserDetailsService implements UserDetailsService, SocialUserDetailsService {
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private PasswordEncoder passwordEncoder;
/*
* (non-Javadoc)
*
* @see org.springframework.security.core.userdetails.UserDetailsService#
* loadUserByUsername(java.lang.String)
*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
logger.info("表单登录用户名:" + username);
return buildUser(username);
}
@Override
public SocialUserDetails loadUserByUserId(String userId) throws UsernameNotFoundException {
logger.info("设计登录用户Id:" + userId);
return buildUser(userId);
}
private SocialUserDetails buildUser(String userId) {
// 根据用户名查找用户信息
//根据查找到的用户信息判断用户是否被冻结
//“123456”是在数据库中查询到的密码
String password = passwordEncoder.encode("123456");
logger.info("数据库密码是:"+password);
return new SocialUser(userId, password,
true, true, true, true,
AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
}
}
对于SocialUser()中四个boolean值得说明,SocialUser是User类的实现,如果为true,isEnabled()账号未被删除,isAccountNonExpired()账号没有过期,isAccountNonLocked()账号没有被锁,isCredentialsNonExpired()身份认证没有过期
PasswordEncoder接口中,encode方法是在你从数据库中查到未加密的密码对其进行加密,matches()方法是Security底层自动调用来对比输入的密码是否与数据库的一致
三、个性化认证流程
自定义登陆界面
我们要处理的是如何解决当前端发送过来的是restful请求的时候返回的是状态码和json数据,当请求的是html页面的时候,返回的是HTML页面。
判断授权形式
自定义登陆成功和失败处理
由于前后端分离的原因,登陆成功和登陆失败处理返回的不是html页面而是json数据,所以我们得自定义登陆成功和失败处理
@Component("imoocAuthenticationSuccessHandler")
public class ImoocAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private ObjectMapper objectMapper;
@Autowired
private SecurityProperties securityProperties;
/*
* (non-Javadoc)
*
* @see org.springframework.security.web.authentication.
* AuthenticationSuccessHandler#onAuthenticationSuccess(javax.servlet.http.
* HttpServletRequest, javax.servlet.http.HttpServletResponse,
* org.springframework.security.core.Authentication)
*/
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
logger.info("登录成功");
if (LoginResponseType.JSON.equals(securityProperties.getBrowser().getLoginType())) { //如果登陆类型要求返回json就执行以下操作,否则执行else返回html
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(objectMapper.writeValueAsString(authentication));
} else {
super.onAuthenticationSuccess(request, response, authentication);
}
}
}
@Component("imoocAuthenctiationFailureHandler")
public class ImoocAuthenctiationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private ObjectMapper objectMapper;
@Autowired
private SecurityProperties securityProperties;
/* (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 request, HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException {
logger.info("登录失败");
if (LoginResponseType.JSON.equals(securityProperties.getBrowser().getLoginType())) {
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(objectMapper.writeValueAsString(new SimpleResponse(exception.getMessage())));
}else{
super.onAuthenticationFailure(request, response, exception);
}
}
}
说明:对于securityProperties.getBrowser().getLoginType()需要自己去定义,这样也就可以实现代码重用