spring security增加图形验证码
作者:互联网
前言
在使用Spring Security框架过程中,经常会有这样的需求,即在登录验证时,附带增加额外的数据,如验证码、用户类型等。下面将介绍如何实现。
注:我的工程是在Spring Boot框架基础上的,使用xml方式配置的话请读者自行研究吧。
实现自定义的WebAuthenticationDetails
该类提供了获取用户登录时携带的额外信息的功能,默认实现WebAuthenticationDetails提供了remoteAddress与sessionId信息。开发者可以通过Authentication的getDetails()获取WebAuthenticationDetails。我们编写自定义类CustomWebAuthenticationDetails继承自WebAuthenticationDetails,添加我们关心的数据(以下是一个token字段)。
对于这个需求,网上的解决方案比较多,如使用filter、自定义Provider……
我采用方法是采用增加AuthenticationProvider的方式。具体实现如下:
1、增加WebAuthenticationDetails实现类,保存验证码信息
public class CustomWebAuthenticationDetails extends WebAuthenticationDetails {
private String imageCode;
private String session_imageCode;
private long session_imageTime;
public CustomWebAuthenticationDetails(HttpServletRequest request) {
super(request);
this.imageCode = request.getParameter("imageCode");
this.session_imageCode = (String)request.getSession().getAttribute("session_imageCode");
String session_verifyTime = (String)request.getSession().getAttribute("session_imageTime");
if(session_verifyTime == null) {
this.session_imageTime= 0L;
} else {
this.session_imageTime= Long.parseLong(session_verifyTime);
}
}
public String getImageCode(){
return imageCode;
}
public String getSession_imageCode() {
return session_imageCode;
}
public long getSession_imageTime() {
return session_imageTime;
}
}
注:在登录页面,可将token字段放在form表单中,也可以直接加在url的参数中,进而把额外数据发送给后台。
2、增加AuthenticationDetailsSource实现类
该接口用于在Spring Security登录过程中对用户的登录信息的详细信息进行填充,默认实现是WebAuthenticationDetailsSource,生成上面的默认实现WebAuthenticationDetails。我们编写类实现AuthenticationDetailsSource,用于生成上面自定义的CustomWebAuthenticationDetails。
@Component
public class CustomAuthenticationDetailsSource implements AuthenticationDetailsSource<HttpServletRequest, WebAuthenticationDetails> {
@Override
public WebAuthenticationDetails buildDetails(HttpServletRequest context) {
return new CustomWebAuthenticationDetails(context);
}
}
3、自定义AuthenticationProvider实现类,并添加到验证列表中去
AuthenticationProvider提供登录验证处理逻辑,我们实现该接口编写自己的验证逻辑。
@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
CustomWebAuthenticationDetails details = (CustomWebAuthenticationDetails) authentication.getDetails();
String imageCode = details.getImageCode();
String session_imageCode = details.getSession_imageCode();
long session_imageTime = details.getSession_imageTime();
if(imageCode == null || session_imageCode == null) {
throw new ImageCodeIllegalException("验证码错误");
}
if(!imageCode.equals(session_imageCode)) {
throw new ImageCodeIllegalException("验证码错误");
}else{
long nowTime = System.currentTimeMillis();
if((nowTime - session_imageTime)/1000 > 60) { //大于60s,超时
throw new ImageCodeIllegalException("验证码已超时");
}
}
return null; //如果后续要有验证密码的provider,这里需要直接返回null
}
@Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}
4、在WebSecurityConfigurerAdapter的实现类中增加配置
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Inject
private AuthenticationDetailsSource<HttpServletRequest, WebAuthenticationDetails> authenticationDetailsSource;
@Inject
private AuthenticationProvider customAuthenticationProvider;
@Inject
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(customAuthenticationProvider);//重点
}
@Override
protected void configure(HttpSecurity http) throws Exception {
……
.and()
.formLogin()
.loginProcessingUrl("/api/login")
.usernameParameter("username")
.passwordParameter("password")
.authenticationDetailsSource(authenticationDetailsSource) //重点
.permitAll()
……
}
}
为达到“用后即焚”的效果,在登录成功、失败后续处理的类中增加了清除验证码的操作
@Component
public class AjaxAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
@Autowired
private PasswordService passwordService;
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication)
throws IOException, ServletException {
//移除验证码
request.getSession().removeAttribute("session_verifyObj");
request.getSession().removeAttribute("session_verifyObjTime");
response.setStatus(HttpServletResponse.SC_OK);
}
}
@Component
public class AjaxAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
@Autowired
private PasswordService passwordService;
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException {
//移除验证码
request.getSession().removeAttribute("session_imgeCode");
request.getSession().removeAttribute("session_imageTime");
……
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authentication failed");
}
}
然后在WebSecurityConfigurerAdapter的实现类中增加相关配置
……
.and()
.formLogin()
.loginProcessingUrl("/api/login")
.successHandler(ajaxAuthenticationSuccessHandler) //重点
.failureHandler(ajaxAuthenticationFailureHandler) //重点
.usernameParameter("username")
.passwordParameter("password")
.authenticationDetailsSource(authenticationDetailsSource)
.permitAll()
……
标签:getSession,spring,imageTime,request,验证码,imageCode,session,security,public 来源: https://blog.csdn.net/ningmeng666_c/article/details/120470261