我有一个包含两个方法的控制器。第一个生成一个随机的验证码值,第二个将其与用户编写的输入进行比较。问题是,当多个用户尝试验证验证码值时,最后一次生成的值被正确验证以预览其他用户的生成的值。
@Controller
@RequestMapping
public class CaptchaController {
private Producer captchaProducer = null;
@Autowired
private DataCaptcha dataCaptcha;
@Autowired
public void setCaptchaProducer(Producer captchaProducer) {
this.captchaProducer = captchaProducer;
}
@RequestMapping(value = "/generate-captcha.json", method = RequestMethod.GET, produces = "application/json")
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws IOException {
String captchaText = captchaProducer.createText();
dataCaptcha.setCaptcha(captchaText);
dataCaptcha.setPasoCaptcha(false);
System.out.println("$$$$$$$$$$$$$$$$ "+ dataCaptcha.getCaptcha()); // output: null
BufferedImage bi = captchaProducer.createImage(captchaText);
ServletOutputStream out = response.getOutputStream();
ImageIO.write(bi, "jpg", out);
out.flush();
out.close();
return null;
}
@RequestMapping(value = "/validate-captcha.json", method = RequestMethod.POST, produces = "application/json")
public @ResponseBody Map<String, Object> validarCaptcha(HttpServletRequest request,
@RequestParam(value = "valueCaptcha", defaultValue = "") String valueCaptcha) {
String captchaId = dataCaptcha.getCaptcha();
Boolean rpta = StringUtils.equalsIgnoreCase(captchaId, valueCaptcha);
String message = "";
String messageType = "OK";
Map<String, Object> response = new HashMap<String,Object>();
if (!rpta) {
message = "incorrect captcha";
messageType = "ERROR";
dataCaptcha.setPasoCaptcha(false);
} else {
dataCaptcha.setPasoCaptcha(true);
}
response.put("messageType", messageType);
response.put("message", message);
response.put("object", rpta);
return response;
}
}
该错误是由于@Controller bean单例导致的,我需要在我的bean中设置一个Prototype范围。所以我尝试了不同的方法来做到这一点:
DataCaptcha :
import lombok.Getter;
import lombok.Setter;
@Component
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE, proxyMode = ScopedProxyMode.TARGET_CLASS)
@Getter
@Setter
public class DataCaptcha {
private String captcha;
private boolean pasoCaptcha;
}
没有一个人工作。尝试调试,并在控制器上的这一行
String captchaText = captchaProducer.createText();
dataCaptcha.setCaptcha(captchaText);
captchaText 有一个值,但是在使用 setCaptcha 并检查对象 dataCaptcha 之后, captcha 字段为空。
我正在使用Spring Boot 2.0.3
答案 0 :(得分:0)
我认为您的DataCaptcha变量不应像在控制器中那样是类变量,而应是handleRequest方法中的变量。
然后,使用spring上下文(如您所暗示)执行
DataCaptcha dataCaptcha = ctx.getBean(DataCaptcha.class)
获取原型实例。
答案 1 :(得分:0)
Singleton Bean在其整个生命周期中都保留着对同一原型Bean的引用。没错,您需要将DataCaptcha置于原型范围内,否则它将在threadContexts之间共享,并且多个用户将能够使用同一验证码。而且,您还需要在方法内部拥有它,而不能在类级别拥有它,因为如果在它的类级别上,将只创建一个控制器类的对象(单个bean),并且其关联的DataCaptcha也将是相同的。
正如您已经指出的那样,可以识别webApplicationContext,您需要在方法内部获取DataCaptcha的新本地实例。您可以尝试将唯一的ID添加到DataCaptcha并使用该ID来获取验证码,以进行验证。或者,您可以将其放在服务器端的userSession对象中,并在成功验证后将其清除。