|
|
@ -27,89 +27,171 @@ import com.google.code.kaptcha.Producer;
|
|
|
|
import com.tamguo.util.Result;
|
|
|
|
import com.tamguo.util.Result;
|
|
|
|
import com.tamguo.util.ShiroUtils;
|
|
|
|
import com.tamguo.util.ShiroUtils;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 标识这是一个Spring的控制器类,主要用于处理用户登录相关的Web请求,包括生成验证码、展示登录页面以及处理登录提交等操作。
|
|
|
|
@Controller
|
|
|
|
@Controller
|
|
|
|
public class LoginController {
|
|
|
|
public class LoginController {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 自动注入Producer,用于生成验证码相关的操作,比如创建验证码文本和对应的图片验证码。
|
|
|
|
@Autowired
|
|
|
|
@Autowired
|
|
|
|
private Producer producer;
|
|
|
|
private Producer producer;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 处理生成验证码图片的请求,该请求对应的路径为 "captcha.jpg",用于生成并返回一个图片格式的验证码给客户端显示。
|
|
|
|
|
|
|
|
* 主要步骤包括设置响应头信息(禁止缓存)、指定响应内容类型为图片(JPEG格式),生成验证码文本和对应的图片,
|
|
|
|
|
|
|
|
* 将验证码文本保存到Shiro的会话中以便后续验证,最后将图片通过输出流输出给客户端。
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* @param response HttpServletResponse对象,用于设置响应相关的信息,如响应头、输出流等,以便向客户端返回验证码图片。
|
|
|
|
|
|
|
|
* @throws ServletException 如果在Servlet处理过程中出现异常则抛出,例如设置响应头、获取输出流等操作出现问题时可能抛出此异常。
|
|
|
|
|
|
|
|
* @throws IOException 如果在读写图片数据到输出流等I/O操作过程中出现异常则抛出。
|
|
|
|
|
|
|
|
*/
|
|
|
|
@RequestMapping("captcha.jpg")
|
|
|
|
@RequestMapping("captcha.jpg")
|
|
|
|
public void captcha(HttpServletResponse response) throws ServletException, IOException {
|
|
|
|
public void captcha(HttpServletResponse response) throws ServletException, IOException {
|
|
|
|
|
|
|
|
// 设置响应头,禁止客户端缓存验证码图片,确保每次获取的验证码都是新生成的。
|
|
|
|
response.setHeader("Cache-Control", "no-store, no-cache");
|
|
|
|
response.setHeader("Cache-Control", "no-store, no-cache");
|
|
|
|
|
|
|
|
// 设置响应的内容类型为JPEG格式的图片,告知客户端返回的数据是图片类型,以便正确解析和显示。
|
|
|
|
response.setContentType("image/jpeg");
|
|
|
|
response.setContentType("image/jpeg");
|
|
|
|
// 生成文字验证码
|
|
|
|
|
|
|
|
|
|
|
|
// 生成验证码的文本内容,通常是由数字、字母等组成的随机字符串,具体生成规则由所使用的验证码生成组件(这里是Producer)决定。
|
|
|
|
String text = producer.createText();
|
|
|
|
String text = producer.createText();
|
|
|
|
// 生成图片验证码
|
|
|
|
// 根据生成的验证码文本创建对应的图片验证码,生成的是一个BufferedImage类型的图片对象,包含了验证码文本的可视化表示形式。
|
|
|
|
BufferedImage image = producer.createImage(text);
|
|
|
|
BufferedImage image = producer.createImage(text);
|
|
|
|
// 保存到shiro session
|
|
|
|
|
|
|
|
|
|
|
|
// 将生成的验证码文本保存到Shiro的会话中,以Constants.KAPTCHA_SESSION_KEY作为键,方便后续在验证用户输入的验证码时从会话中获取并比对。
|
|
|
|
ShiroUtils.setSessionAttribute(Constants.KAPTCHA_SESSION_KEY, text);
|
|
|
|
ShiroUtils.setSessionAttribute(Constants.KAPTCHA_SESSION_KEY, text);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 获取ServletResponse的输出流,用于将生成的图片数据写入到响应中,发送给客户端进行显示。
|
|
|
|
ServletOutputStream out = response.getOutputStream();
|
|
|
|
ServletOutputStream out = response.getOutputStream();
|
|
|
|
|
|
|
|
// 使用ImageIO将BufferedImage格式的图片以JPEG格式写入到输出流中,实现将验证码图片返回给客户端的功能。
|
|
|
|
ImageIO.write(image, "jpg", out);
|
|
|
|
ImageIO.write(image, "jpg", out);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 处理登录页面的GET请求,设置视图名称为"login",意味着会查找并渲染名为"login"的视图模板(例如JSP、Thymeleaf等模板文件,具体取决于项目配置)返回给客户端展示登录页面,
|
|
|
|
|
|
|
|
* 同时向视图模型中添加一个名为"isVerifyCode",值为"0"的属性,可能用于前端页面判断是否显示验证码相关的逻辑(具体用途根据前端代码确定)。
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* @param model 用于传递数据到视图的ModelAndView对象,在这里向其添加了登录页面相关的数据(如是否显示验证码的标识)。
|
|
|
|
|
|
|
|
* @return 返回包含视图名称和相关数据的ModelAndView对象,以便Spring的视图解析器根据该名称查找并渲染相应的视图展示给用户。
|
|
|
|
|
|
|
|
*/
|
|
|
|
@RequestMapping(value = "/login", method = RequestMethod.GET)
|
|
|
|
@RequestMapping(value = "/login", method = RequestMethod.GET)
|
|
|
|
public ModelAndView login(ModelAndView model){
|
|
|
|
public ModelAndView login(ModelAndView model) {
|
|
|
|
model.setViewName("login");
|
|
|
|
model.setViewName("login");
|
|
|
|
model.addObject("isVerifyCode" , "0");
|
|
|
|
model.addObject("isVerifyCode", "0");
|
|
|
|
return model;
|
|
|
|
return model;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 处理用户提交登录信息的POST请求,接收用户名、密码和验证码等参数,进行登录验证相关的一系列操作,包括验证码验证、Shiro框架的登录认证等,
|
|
|
|
|
|
|
|
* 根据验证结果设置相应的提示信息,并返回登录页面或者重定向到登录成功后的页面(如果登录成功)。
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* @param username 用户输入的用户名,用于登录认证。
|
|
|
|
|
|
|
|
* @param password 用户输入的密码,用于登录认证。
|
|
|
|
|
|
|
|
* @param verifyCode 用户输入的验证码,用于与生成并保存在会话中的验证码进行比对验证。
|
|
|
|
|
|
|
|
* @param model 用于传递数据到视图的ModelAndView对象,根据登录验证结果向其添加相应的提示信息、用户名等数据,以便在登录页面展示给用户。
|
|
|
|
|
|
|
|
* @param session 当前的HttpSession对象,用于获取或设置会话相关的属性,如保存登录后的用户信息等操作。
|
|
|
|
|
|
|
|
* @param response HttpServletResponse对象,用于在登录成功时进行重定向操作,将用户引导到登录成功后的页面。
|
|
|
|
|
|
|
|
* @throws IOException 如果在重定向等操作过程中出现I/O异常则抛出,例如向客户端发送重定向响应时可能出现的异常情况。
|
|
|
|
|
|
|
|
*/
|
|
|
|
@RequestMapping(value = "/submitLogin", method = RequestMethod.POST)
|
|
|
|
@RequestMapping(value = "/submitLogin", method = RequestMethod.POST)
|
|
|
|
public ModelAndView submitLogin(String username , String password , String verifyCode , ModelAndView model , HttpSession session , HttpServletResponse response) throws IOException{
|
|
|
|
public ModelAndView submitLogin(String username, String password, String verifyCode, ModelAndView model,
|
|
|
|
|
|
|
|
HttpSession session, HttpServletResponse response) throws IOException {
|
|
|
|
|
|
|
|
// 创建一个表示登录结果的Result对象,初始化为成功状态(这里先设置为成功,后续根据实际验证情况进行修改),其内容暂时为空。
|
|
|
|
Result result = Result.successResult(null);
|
|
|
|
Result result = Result.successResult(null);
|
|
|
|
if(StringUtils.isEmpty(verifyCode)) {
|
|
|
|
|
|
|
|
|
|
|
|
// 判断用户输入的验证码是否为空,如果为空则表示用户未输入验证码,设置相应的错误提示信息到Result对象中。
|
|
|
|
|
|
|
|
if (StringUtils.isEmpty(verifyCode)) {
|
|
|
|
result = Result.result(202, null, "请输入验证码");
|
|
|
|
result = Result.result(202, null, "请输入验证码");
|
|
|
|
} else if(StringUtils.isNotEmpty(verifyCode)){
|
|
|
|
} else if (StringUtils.isNotEmpty(verifyCode)) {
|
|
|
|
|
|
|
|
// 如果用户输入了验证码,从Shiro会话中获取之前生成并保存的验证码文本,用于和用户输入的验证码进行比对验证。
|
|
|
|
String kaptcha = ShiroUtils.getKaptcha(Constants.KAPTCHA_SESSION_KEY);
|
|
|
|
String kaptcha = ShiroUtils.getKaptcha(Constants.KAPTCHA_SESSION_KEY);
|
|
|
|
|
|
|
|
// 忽略大小写比较用户输入的验证码和会话中的验证码是否一致,如果不一致则表示验证码错误,设置相应的错误提示信息到Result对象中。
|
|
|
|
if (!verifyCode.equalsIgnoreCase(kaptcha)) {
|
|
|
|
if (!verifyCode.equalsIgnoreCase(kaptcha)) {
|
|
|
|
result = Result.result(205, null, "验证码错误");
|
|
|
|
result = Result.result(205, null, "验证码错误");
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
|
|
|
|
// 如果验证码验证通过,获取Shiro的Subject对象,它代表了当前执行的用户主体,用于后续进行登录认证等操作。
|
|
|
|
Subject subject = ShiroUtils.getSubject();
|
|
|
|
Subject subject = ShiroUtils.getSubject();
|
|
|
|
|
|
|
|
// 创建一个UsernamePasswordToken对象,将用户输入的用户名和密码封装进去,作为登录认证的凭证传递给Shiro框架。
|
|
|
|
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
|
|
|
|
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
|
|
|
|
// 通过Subject对象发起登录认证操作,Shiro框架会根据配置的认证逻辑(如从数据库查询用户信息并比对密码等)进行验证。
|
|
|
|
subject.login(token);
|
|
|
|
subject.login(token);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 如果登录成功,将登录后的用户信息保存到HttpSession中,方便在后续的请求处理中获取当前登录用户的相关信息,键为"currMember"。
|
|
|
|
session.setAttribute("currMember", ShiroUtils.getMember());
|
|
|
|
session.setAttribute("currMember", ShiroUtils.getMember());
|
|
|
|
|
|
|
|
// 重定向到登录成功后的页面(这里是"member/index.html",可能是会员相关的首页之类的页面,具体根据业务需求确定)。
|
|
|
|
response.sendRedirect("member/index.html");
|
|
|
|
response.sendRedirect("member/index.html");
|
|
|
|
|
|
|
|
// 登录成功后直接返回null,因为已经进行了重定向操作,不需要再返回视图相关的内容了。
|
|
|
|
return null;
|
|
|
|
return null;
|
|
|
|
} catch (UnknownAccountException e) {
|
|
|
|
} catch (UnknownAccountException e) {
|
|
|
|
|
|
|
|
// 如果Shiro认证过程中抛出UnknownAccountException异常,表示用户名不存在或者未找到对应的用户信息,设置相应的错误提示信息到Result对象中。
|
|
|
|
result = Result.result(201, null, "用户名或密码有误,请重新输入或找回密码");
|
|
|
|
result = Result.result(201, null, "用户名或密码有误,请重新输入或找回密码");
|
|
|
|
} catch (IncorrectCredentialsException e) {
|
|
|
|
} catch (IncorrectCredentialsException e) {
|
|
|
|
|
|
|
|
// 如果Shiro认证过程中抛出IncorrectCredentialsException异常,表示密码错误,设置相应的错误提示信息到Result对象中。
|
|
|
|
result = Result.result(202, null, "用户名或密码有误,请重新输入或找回密码");
|
|
|
|
result = Result.result(202, null, "用户名或密码有误,请重新输入或找回密码");
|
|
|
|
} catch (LockedAccountException e) {
|
|
|
|
} catch (LockedAccountException e) {
|
|
|
|
|
|
|
|
// 如果Shiro认证过程中抛出LockedAccountException异常,表示账号被锁定,设置相应的错误提示信息到Result对象中。
|
|
|
|
result = Result.result(203, null, "账号被锁定");
|
|
|
|
result = Result.result(203, null, "账号被锁定");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 如果登录验证未通过(出现各种错误情况),设置视图名称为"login",表示返回登录页面展示给用户相应的错误提示信息。
|
|
|
|
model.setViewName("login");
|
|
|
|
model.setViewName("login");
|
|
|
|
|
|
|
|
// 将登录结果的状态码添加到视图模型中,方便前端页面根据状态码进行不同的提示信息展示等逻辑处理。
|
|
|
|
model.addObject("code", result.getCode());
|
|
|
|
model.addObject("code", result.getCode());
|
|
|
|
model.addObject("msg" , result.getMessage());
|
|
|
|
// 将登录结果的提示信息添加到视图模型中,以便在登录页面展示给用户具体的错误原因等内容。
|
|
|
|
|
|
|
|
model.addObject("msg", result.getMessage());
|
|
|
|
|
|
|
|
// 将用户输入的用户名添加到视图模型中,可能用于前端页面保留用户之前输入的用户名,提升用户体验等用途(具体根据前端需求确定)。
|
|
|
|
model.addObject("username", username);
|
|
|
|
model.addObject("username", username);
|
|
|
|
return model;
|
|
|
|
return model;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 处理小型登录(可能是用于移动端或者特定场景下简化的登录方式)的GET请求,接收用户名、密码和验证码等参数,进行登录验证相关的一系列操作,
|
|
|
|
|
|
|
|
* 根据验证结果返回相应的Result对象,包含登录成功后的用户信息(如果登录成功)或者错误提示信息(如果登录失败)。
|
|
|
|
|
|
|
|
* 与submitLogin方法类似,也进行了验证码验证、Shiro框架的登录认证以及各种异常情况的处理,但这里是通过ResponseBody注解直接返回Result对象给客户端,而不是返回视图相关内容。
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* @param username 用户输入的用户名,用于登录认证。
|
|
|
|
|
|
|
|
* @param password 用户输入的密码,用于登录认证。
|
|
|
|
|
|
|
|
* @param captcha 用户输入的验证码,用于与生成并保存在会话中的验证码进行比对验证。
|
|
|
|
|
|
|
|
* @param model 用于传递数据到视图的ModelAndView对象(这里在该方法中未实际使用到,可能是为了与其他类似方法保持参数形式一致而添加的)。
|
|
|
|
|
|
|
|
* @param session 当前的HttpSession对象,用于获取或设置会话相关的属性,如保存登录后的用户信息等操作。
|
|
|
|
|
|
|
|
* @return 返回表示登录结果的Result对象,包含登录成功后的用户信息或者相应的错误提示信息,客户端可根据返回结果进行后续的处理,如展示提示信息或者跳转到相应页面等。
|
|
|
|
|
|
|
|
*/
|
|
|
|
@RequestMapping(value = "/miniLogin", method = RequestMethod.GET)
|
|
|
|
@RequestMapping(value = "/miniLogin", method = RequestMethod.GET)
|
|
|
|
@ResponseBody
|
|
|
|
@ResponseBody
|
|
|
|
public Result miniLogin(String username , String password , String captcha, ModelAndView model , HttpSession session) {
|
|
|
|
public Result miniLogin(String username, String password, String captcha, ModelAndView model,
|
|
|
|
|
|
|
|
HttpSession session) {
|
|
|
|
Result result = null;
|
|
|
|
Result result = null;
|
|
|
|
if(StringUtils.isEmpty(captcha)) {
|
|
|
|
// 判断用户输入的验证码是否为空,如果为空则表示用户未输入验证码,设置相应的错误提示信息到Result对象中。
|
|
|
|
|
|
|
|
if (StringUtils.isEmpty(captcha)) {
|
|
|
|
result = Result.result(204, null, "请输入验证码");
|
|
|
|
result = Result.result(204, null, "请输入验证码");
|
|
|
|
} else if(StringUtils.isNotEmpty(captcha)){
|
|
|
|
} else if (StringUtils.isNotEmpty(captcha)) {
|
|
|
|
|
|
|
|
// 如果用户输入了验证码,从Shiro会话中获取之前生成并保存的验证码文本,用于和用户输入的验证码进行比对验证。
|
|
|
|
String kaptcha = ShiroUtils.getKaptcha(Constants.KAPTCHA_SESSION_KEY);
|
|
|
|
String kaptcha = ShiroUtils.getKaptcha(Constants.KAPTCHA_SESSION_KEY);
|
|
|
|
|
|
|
|
// 忽略大小写比较用户输入的验证码和会话中的验证码是否一致,如果不一致则表示验证码错误,设置相应的错误提示信息到Result对象中。
|
|
|
|
if (!captcha.equalsIgnoreCase(kaptcha)) {
|
|
|
|
if (!captcha.equalsIgnoreCase(kaptcha)) {
|
|
|
|
result = Result.result(205, null, "验证码错误");
|
|
|
|
result = Result.result(205, null, "验证码错误");
|
|
|
|
}else {
|
|
|
|
} else {
|
|
|
|
|
|
|
|
// 如果验证码验证通过,获取Shiro的Subject对象,它代表了当前执行的用户主体,用于后续进行登录认证等操作。
|
|
|
|
Subject subject = ShiroUtils.getSubject();
|
|
|
|
Subject subject = ShiroUtils.getSubject();
|
|
|
|
|
|
|
|
// 创建一个UsernamePasswordToken对象,将用户输入的用户名和密码封装进去,作为登录认证的凭证传递给Shiro框架。
|
|
|
|
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
|
|
|
|
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
|
|
|
|
// 通过Subject对象发起登录认证操作,Shiro框架会根据配置的认证逻辑(如从数据库查询用户信息并比对密码等)进行验证。
|
|
|
|
subject.login(token);
|
|
|
|
subject.login(token);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 如果登录成功,将登录后的用户信息保存到HttpSession中,方便在后续的请求处理中获取当前登录用户的相关信息,键为"currMember"。
|
|
|
|
session.setAttribute("currMember", ShiroUtils.getMember());
|
|
|
|
session.setAttribute("currMember", ShiroUtils.getMember());
|
|
|
|
|
|
|
|
// 创建表示登录成功的Result对象,并将登录后的用户信息设置到Result对象中,以便返回给客户端。
|
|
|
|
result = Result.successResult(ShiroUtils.getMember());
|
|
|
|
result = Result.successResult(ShiroUtils.getMember());
|
|
|
|
} catch (UnknownAccountException e) {
|
|
|
|
} catch (UnknownAccountException e) {
|
|
|
|
|
|
|
|
// 如果Shiro认证过程中抛出UnknownAccountException异常,表示用户名不存在或者未找到对应的用户信息,设置相应的错误提示信息到Result对象中。
|
|
|
|
result = Result.result(201, null, "用户名或密码有误,请重新输入或找回密码");
|
|
|
|
result = Result.result(201, null, "用户名或密码有误,请重新输入或找回密码");
|
|
|
|
} catch (IncorrectCredentialsException e) {
|
|
|
|
} catch (IncorrectCredentialsException e) {
|
|
|
|
|
|
|
|
// 如果Shiro认证过程中抛出IncorrectCredentialsException异常,表示密码错误,设置相应的错误提示信息到Result对象中。
|
|
|
|
result = Result.result(202, null, "用户名或密码有误,请重新输入或找回密码");
|
|
|
|
result = Result.result(202, null, "用户名或密码有误,请重新输入或找回密码");
|
|
|
|
} catch (LockedAccountException e) {
|
|
|
|
} catch (LockedAccountException e) {
|
|
|
|
|
|
|
|
// 如果Shiro认证过程中抛出LockedAccountException异常,表示账号被锁定,设置相应的错误提示信息到Result对象中。
|
|
|
|
result = Result.result(203, null, "账号被锁定");
|
|
|
|
result = Result.result(203, null, "账号被锁定");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|