验证码登录实现
在用户登录的时候,需要做安全校验,加验证码是普遍的做法,分析一下ruoyi开源框架的验证码登录实现逻辑
当用户打开登录页面的时候,就要发送请求,去后台生成一个验证码传到前台
1.
@RestController
public class CaptchaController {
@Autowired
private RedisService redisService;
/**
* 生成验证码工具类
*/
@GetMapping("/creatorCode")
public Result creatorCode(HttpServletResponse response) throws IOException {
// 生成验证码随机4位字符串
String verifyCode = VerifyCodeUtils.generateVerifyCode(4);
// 生成uuid 17ce79633eea49f6a1d4035505078fd8
String uuid = UuIdUtils.createUUID();
//生成的UUID,加上captcha_codes:最为键,当做redis中的key存储code
String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;
redisCache.setCacheObject(verifyKey, verifyCode, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
// 生成图片
int w = 111, h = 36;
ByteArrayOutputStream stream = new ByteArrayOutputStream();
VerifyCodeUtils.outputImage(w, h, stream, verifyCode);
try {
AjaxResult ajax = AjaxResult.success();
ajax.put("uuid", uuid);
ajax.put("img", Base64.encode(stream.toByteArray()));
return ajax;
} catch (Exception e) {
e.printStackTrace();
return AjaxResult.error(e.getMessage());
} finally {
stream.close();
}
}
}
//已生成的Key和对应的Value

2.用户输入账号密码验证码,发送请求到后端进行校验 访问:http://localhost/login
/**
* 登录方法
* @param loginBody 登陆信息
* @return 结果
*/
@PostMapping("/login")
public AjaxResult login(@RequestBody LoginBody loginBody) {
AjaxResult ajax = AjaxResult.success();
// 生成令牌
String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),
loginBody.getUuid());
ajax.put(Constants.TOKEN, token);
return ajax;
}
SysLoginService 这个类会进行用户信息的校@Component
public class SysLoginService
{
@Autowired
private TokenService tokenService;
@Resource
private AuthenticationManager authenticationManager;
@Autowired
private RedisCache redisCache;
/**
* 登录验证
*
* @param username 用户名
* @param password 密码
* @param captcha 验证码
* @param uuid 唯一标识
* @return 结果
*/
public String login(String username, String password, String code, String uuid)
{
//用户携带过来的:uuid17ce79633eea49f6a1d4035505078fd8
//当登录页面打开的时候,这个uuid和验证码就已经携带发送给页面
System.out.println("用户携带过来的UUID:"+uuid);
//拿到uuid拼接Constants.CAPTCHA_CODE_KEY
String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;
//拿到拼接后的数据作为条件查询redis
String captcha = redisCache.getCacheObject(verifyKey);
//redis中删除验证码
redisCache.deleteObject(verifyKey);
//校验验证码
if (captcha == null)
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));
throw new CaptchaExpireException();
}
if (!code.equalsIgnoreCase(captcha))
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
throw new CaptchaException();
}
// 用户验证
Authentication authentication = null;
try
{
// 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
authentication = authenticationManager
.authenticate(new UsernamePasswordAuthenticationToken(username, password));
}
catch (Exception e)
{
if (e instanceof BadCredentialsException)
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
throw new UserPasswordNotMatchException();
}
else
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
throw new CustomException(e.getMessage());
}
}
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
//校验完成后得到 loginUser对象, 基于这个对象生成token,完成登录
LoginUser loginUser = (LoginUser) authentication.getPrincipal();
// 生成token
return tokenService.createToken(loginUser);
}
}
自己一些小总结,还在学习阶段

浙公网安备 33010602011771号