提交 7f27d3b8 编写于 作者: 江南一点雨

添加登录验证码

上级 a76a5a9a
......@@ -7,7 +7,6 @@ import org.javaboy.vhr.service.HrService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.*;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
......@@ -19,10 +18,10 @@ import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import javax.servlet.ServletException;
......@@ -48,6 +47,8 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
CustomFilterInvocationSecurityMetadataSource customFilterInvocationSecurityMetadataSource;
@Autowired
CustomUrlDecisionManager customUrlDecisionManager;
@Autowired
VerificationCodeFilter verificationCodeFilter;
@Bean
PasswordEncoder passwordEncoder() {
......@@ -61,11 +62,12 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/login","/css/**","/js/**","/index.html","/img/**","/fonts/**","/favicon.ico");
web.ignoring().antMatchers("/login","/css/**","/js/**","/index.html","/img/**","/fonts/**","/favicon.ico","/verifyCode");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(verificationCodeFilter, UsernamePasswordAuthenticationFilter.class);
http.authorizeRequests()
// .anyRequest().authenticated()
.withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
......
package org.javaboy.vhr.config;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Random;
/**
* @作者 江南一点雨
* @公众号 江南一点雨
* @微信号 a_java_boy
* @GitHub https://github.com/lenve
* @博客 http://wangsong.blog.csdn.net
* @网站 http://www.javaboy.org
* @时间 2019-09-29 7:37
*
* 生成验证码的工具类
*/
public class VerificationCode {
private int width = 100;// 生成验证码图片的宽度
private int height = 30;// 生成验证码图片的高度
private String[] fontNames = { "宋体", "楷体", "隶书", "微软雅黑" };
private Color bgColor = new Color(255, 255, 255);// 定义验证码图片的背景颜色为白色
private Random random = new Random();
private String codes = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
private String text;// 记录随机字符串
/**
* 获取一个随意颜色
*
* @return
*/
private Color randomColor() {
int red = random.nextInt(150);
int green = random.nextInt(150);
int blue = random.nextInt(150);
return new Color(red, green, blue);
}
/**
* 获取一个随机字体
*
* @return
*/
private Font randomFont() {
String name = fontNames[random.nextInt(fontNames.length)];
int style = random.nextInt(4);
int size = random.nextInt(5) + 24;
return new Font(name, style, size);
}
/**
* 获取一个随机字符
*
* @return
*/
private char randomChar() {
return codes.charAt(random.nextInt(codes.length()));
}
/**
* 创建一个空白的BufferedImage对象
*
* @return
*/
private BufferedImage createImage() {
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = (Graphics2D) image.getGraphics();
g2.setColor(bgColor);// 设置验证码图片的背景颜色
g2.fillRect(0, 0, width, height);
return image;
}
public BufferedImage getImage() {
BufferedImage image = createImage();
Graphics2D g2 = (Graphics2D) image.getGraphics();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 4; i++) {
String s = randomChar() + "";
sb.append(s);
g2.setColor(randomColor());
g2.setFont(randomFont());
float x = i * width * 1.0f / 4;
g2.drawString(s, x, height - 8);
}
this.text = sb.toString();
drawLine(image);
return image;
}
/**
* 绘制干扰线
*
* @param image
*/
private void drawLine(BufferedImage image) {
Graphics2D g2 = (Graphics2D) image.getGraphics();
int num = 5;
for (int i = 0; i < num; i++) {
int x1 = random.nextInt(width);
int y1 = random.nextInt(height);
int x2 = random.nextInt(width);
int y2 = random.nextInt(height);
g2.setColor(randomColor());
g2.setStroke(new BasicStroke(1.5f));
g2.drawLine(x1, y1, x2, y2);
}
}
public String getText() {
return text;
}
public static void output(BufferedImage image, OutputStream out) throws IOException {
ImageIO.write(image, "JPEG", out);
}
}
\ No newline at end of file
package org.javaboy.vhr.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.javaboy.vhr.model.RespBean;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* @作者 江南一点雨
* @公众号 江南一点雨
* @微信号 a_java_boy
* @GitHub https://github.com/lenve
* @博客 http://wangsong.blog.csdn.net
* @网站 http://www.javaboy.org
* @时间 2020-02-28 22:03
*/
@Component
public class VerificationCodeFilter extends GenericFilter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) servletRequest;
HttpServletResponse resp = (HttpServletResponse) servletResponse;
if ("POST".equals(req.getMethod()) && "/doLogin".equals(req.getServletPath())) {
//登录请求
String code = req.getParameter("code");
String verify_code = (String) req.getSession().getAttribute("verify_code");
if (code == null || verify_code == null || "".equals(code) || !verify_code.toLowerCase().equals(code.toLowerCase())) {
//验证码不正确
resp.setContentType("application/json;charset=utf-8");
PrintWriter out = resp.getWriter();
out.write(new ObjectMapper().writeValueAsString(RespBean.error("验证码填写错误")));
out.flush();
out.close();
return;
} else {
filterChain.doFilter(req, resp);
}
} else {
filterChain.doFilter(req, resp);
}
}
}
package org.javaboy.vhr.controller;
import org.javaboy.vhr.config.VerificationCode;
import org.javaboy.vhr.model.RespBean;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.image.BufferedImage;
import java.io.IOException;
/**
* @作者 江南一点雨
* @公众号 江南一点雨
......@@ -20,4 +25,13 @@ public class LoginController {
public RespBean login() {
return RespBean.error("尚未登录,请登录!");
}
@GetMapping("/verifyCode")
public void verifyCode(HttpSession session, HttpServletResponse resp) throws IOException {
VerificationCode code = new VerificationCode();
BufferedImage image = code.getImage();
String text = code.getText();
session.setAttribute("verify_code", text);
VerificationCode.output(image,resp.getOutputStream());
}
}
.loginContainer{border-radius:15px;background-clip:padding-box;margin:180px auto;width:350px;padding:15px 35px 15px 35px;background:#fff;border:1px solid #eaeaea;-webkit-box-shadow:0 0 25px #cac6c6;box-shadow:0 0 25px #cac6c6}.loginTitle{margin:15px auto 20px auto;text-align:center;color:#505458}.loginRemember{text-align:left;margin:0 0 15px 0}.el-form-item__content{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.homeRouterView{margin-top:10px}.homeWelcome{text-align:center;font-size:30px;font-family:华文行楷;color:#409eff;padding-top:50px}.homeHeader{background-color:#409eff;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;padding:0 15px;-webkit-box-sizing:border-box;box-sizing:border-box}.homeHeader .title{font-size:30px;font-family:华文行楷;color:#fff}.homeHeader .userInfo{cursor:pointer}.el-dropdown-link img{width:48px;height:48px;border-radius:24px;margin-left:8px}.el-dropdown-link{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}#card[data-v-7ee9dd77]{padding:12px}#card .avatar[data-v-7ee9dd77]{width:40px;height:40px;vertical-align:middle}#card .name[data-v-7ee9dd77]{display:inline-block;padding:10px;margin-bottom:15px;font-size:16px}#card .search[data-v-7ee9dd77]{background:#26292e;height:30px;line-height:30px;padding:0 10px;border:1px solid #3a3a3a;border-radius:4px;outline:none;color:#fff}#list li[data-v-5d7c9762]{padding:16px 15px;border-bottom:1px solid #292c33;cursor:pointer;list-style:none}#list li[data-v-5d7c9762]:hover{background-color:hsla(0,0%,100%,.03)}#list li.active[data-v-5d7c9762]{background-color:hsla(0,0%,100%,.1)}#list .avatar[data-v-5d7c9762]{border-radius:2px;width:30px;height:30px;vertical-align:middle}#list .name[data-v-5d7c9762]{display:inline-block;margin-left:15px;margin-top:0;margin-bottom:0}#message[data-v-9f2df1e6]{padding:15px;max-height:68%;overflow-y:scroll}#message ul[data-v-9f2df1e6]{list-style-type:none;padding-left:0}#message ul li[data-v-9f2df1e6]{margin-bottom:15px}#message .time[data-v-9f2df1e6]{text-align:center;margin:7px 0}#message .time>span[data-v-9f2df1e6]{display:inline-block;padding:0 18px;font-size:12px;color:#fff;background-color:#dcdcdc;border-radius:2px}#message .main .avatar[data-v-9f2df1e6]{float:left;margin:0 10px 0 0;border-radius:3px;width:30px;height:30px}#message .main .text[data-v-9f2df1e6]{display:inline-block;padding:0 10px;max-width:80%;background-color:#fafafa;border-radius:4px;line-height:30px}#message .self[data-v-9f2df1e6]{text-align:right}#message .self .avatar[data-v-9f2df1e6]{float:right;margin:0 0 0 10px;border-radius:3px;width:30px;height:30px}#message .self .text[data-v-9f2df1e6]{display:inline-block;padding:0 10px;max-width:80%;background-color:#b2e281;border-radius:4px;line-height:30px}#uesrtext[data-v-1e00b6fb]{position:absolute;bottom:0;right:0;width:100%;height:30%;border-top:1px solid #ddd}#uesrtext>textarea[data-v-1e00b6fb]{padding:10px;width:100%;height:100%;border:none;outline:none}#app[data-v-67ef771e]{margin:20px auto;width:800px;height:600px;overflow:hidden;border-radius:10px}#app .main[data-v-67ef771e],#app .sidebar[data-v-67ef771e]{height:100%}#app .sidebar[data-v-67ef771e]{float:left;color:#f4f4f4;background-color:#2e3238;width:200px}#app .main[data-v-67ef771e]{position:relative;overflow:hidden;background-color:#eee}
\ No newline at end of file
.loginContainer{border-radius:15px;background-clip:padding-box;margin:180px auto;width:350px;padding:15px 35px 15px 35px;background:#fff;border:1px solid #eaeaea;-webkit-box-shadow:0 0 25px #cac6c6;box-shadow:0 0 25px #cac6c6}.loginTitle{margin:15px auto 20px auto;text-align:center;color:#505458}.loginRemember{text-align:left;margin:0 0 15px 0}.homeRouterView{margin-top:10px}.homeWelcome{text-align:center;font-size:30px;font-family:华文行楷;color:#409eff;padding-top:50px}.homeHeader{background-color:#409eff;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;padding:0 15px;-webkit-box-sizing:border-box;box-sizing:border-box}.homeHeader .title{font-size:30px;font-family:华文行楷;color:#fff}.homeHeader .userInfo{cursor:pointer}.el-dropdown-link img{width:48px;height:48px;border-radius:24px;margin-left:8px}.el-dropdown-link{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}#card[data-v-7ee9dd77]{padding:12px}#card .avatar[data-v-7ee9dd77]{width:40px;height:40px;vertical-align:middle}#card .name[data-v-7ee9dd77]{display:inline-block;padding:10px;margin-bottom:15px;font-size:16px}#card .search[data-v-7ee9dd77]{background:#26292e;height:30px;line-height:30px;padding:0 10px;border:1px solid #3a3a3a;border-radius:4px;outline:none;color:#fff}#list li[data-v-5d7c9762]{padding:16px 15px;border-bottom:1px solid #292c33;cursor:pointer;list-style:none}#list li[data-v-5d7c9762]:hover{background-color:hsla(0,0%,100%,.03)}#list li.active[data-v-5d7c9762]{background-color:hsla(0,0%,100%,.1)}#list .avatar[data-v-5d7c9762]{border-radius:2px;width:30px;height:30px;vertical-align:middle}#list .name[data-v-5d7c9762]{display:inline-block;margin-left:15px;margin-top:0;margin-bottom:0}#message[data-v-9f2df1e6]{padding:15px;max-height:68%;overflow-y:scroll}#message ul[data-v-9f2df1e6]{list-style-type:none;padding-left:0}#message ul li[data-v-9f2df1e6]{margin-bottom:15px}#message .time[data-v-9f2df1e6]{text-align:center;margin:7px 0}#message .time>span[data-v-9f2df1e6]{display:inline-block;padding:0 18px;font-size:12px;color:#fff;background-color:#dcdcdc;border-radius:2px}#message .main .avatar[data-v-9f2df1e6]{float:left;margin:0 10px 0 0;border-radius:3px;width:30px;height:30px}#message .main .text[data-v-9f2df1e6]{display:inline-block;padding:0 10px;max-width:80%;background-color:#fafafa;border-radius:4px;line-height:30px}#message .self[data-v-9f2df1e6]{text-align:right}#message .self .avatar[data-v-9f2df1e6]{float:right;margin:0 0 0 10px;border-radius:3px;width:30px;height:30px}#message .self .text[data-v-9f2df1e6]{display:inline-block;padding:0 10px;max-width:80%;background-color:#b2e281;border-radius:4px;line-height:30px}#uesrtext[data-v-1e00b6fb]{position:absolute;bottom:0;right:0;width:100%;height:30%;border-top:1px solid #ddd}#uesrtext>textarea[data-v-1e00b6fb]{padding:10px;width:100%;height:100%;border:none;outline:none}#app[data-v-67ef771e]{margin:20px auto;width:800px;height:600px;overflow:hidden;border-radius:10px}#app .main[data-v-67ef771e],#app .sidebar[data-v-67ef771e]{height:100%}#app .sidebar[data-v-67ef771e]{float:left;color:#f4f4f4;background-color:#2e3238;width:200px}#app .main[data-v-67ef771e]{position:relative;overflow:hidden;background-color:#eee}
\ No newline at end of file
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><link rel=icon href=/favicon.ico><title>vuehr</title><link href=/css/chunk-0c17a57a.42916da5.css rel=prefetch><link href=/css/chunk-64435448.b098027b.css rel=prefetch><link href=/js/chunk-0c17a57a.9f994633.js rel=prefetch><link href=/js/chunk-18458ebc.86c8ddb1.js rel=prefetch><link href=/js/chunk-2d0d03c8.3a093d55.js rel=prefetch><link href=/js/chunk-2d237c54.0b312051.js rel=prefetch><link href=/js/chunk-4e552d82.72730c25.js rel=prefetch><link href=/js/chunk-54277bc7.cec1101d.js rel=prefetch><link href=/js/chunk-64435448.f802539e.js rel=prefetch><link href=/js/chunk-a3fdbb9c.cacee110.js rel=prefetch><link href=/css/app.8ec6a717.css rel=preload as=style><link href=/css/chunk-vendors.9948ce82.css rel=preload as=style><link href=/js/app.3b28e426.js rel=preload as=script><link href=/js/chunk-vendors.11959501.js rel=preload as=script><link href=/css/chunk-vendors.9948ce82.css rel=stylesheet><link href=/css/app.8ec6a717.css rel=stylesheet></head><body style="margin:0px;padding: 0px;"><noscript><strong>We're sorry but vuehr doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script src=/js/chunk-vendors.11959501.js></script><script src=/js/app.3b28e426.js></script></body></html>
\ No newline at end of file
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><link rel=icon href=/favicon.ico><title>vuehr</title><link href=/css/chunk-0c17a57a.42916da5.css rel=prefetch><link href=/css/chunk-64435448.3755e146.css rel=prefetch><link href=/js/chunk-0c17a57a.9f994633.js rel=prefetch><link href=/js/chunk-18458ebc.86c8ddb1.js rel=prefetch><link href=/js/chunk-2d0d03c8.3a093d55.js rel=prefetch><link href=/js/chunk-2d237c54.0b312051.js rel=prefetch><link href=/js/chunk-4e552d82.72730c25.js rel=prefetch><link href=/js/chunk-54277bc7.cec1101d.js rel=prefetch><link href=/js/chunk-64435448.0dc99191.js rel=prefetch><link href=/js/chunk-a3fdbb9c.cacee110.js rel=prefetch><link href=/css/app.1e749142.css rel=preload as=style><link href=/css/chunk-vendors.9948ce82.css rel=preload as=style><link href=/js/app.cf8720da.js rel=preload as=script><link href=/js/chunk-vendors.11959501.js rel=preload as=script><link href=/css/chunk-vendors.9948ce82.css rel=stylesheet><link href=/css/app.1e749142.css rel=stylesheet></head><body style="margin:0px;padding: 0px;"><noscript><strong>We're sorry but vuehr doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script src=/js/chunk-vendors.11959501.js></script><script src=/js/app.cf8720da.js></script></body></html>
\ No newline at end of file
因为 它太大了无法显示 source diff 。你可以改为 查看blob
......@@ -16,7 +16,12 @@
</el-form-item>
<el-form-item prop="password">
<el-input size="normal" type="password" v-model="loginForm.password" auto-complete="off"
placeholder="请输入密码" @keydown.enter.native="submitLogin"></el-input>
placeholder="请输入密码"></el-input>
</el-form-item>
<el-form-item prop="code">
<el-input size="normal" type="text" v-model="loginForm.code" auto-complete="off"
placeholder="点击图片更换验证码" @keydown.enter.native="submitLogin" style="width: 250px"></el-input>
<img :src="vcUrl" @click="updateVerifyCode" alt="">
</el-form-item>
<el-checkbox size="normal" class="loginRemember" v-model="checked"></el-checkbox>
<el-button size="normal" type="primary" style="width: 100%;" @click="submitLogin">登录</el-button>
......@@ -31,18 +36,24 @@
data() {
return {
loading: false,
vcUrl: '/verifyCode?time='+new Date(),
loginForm: {
username: 'admin',
password: '123'
password: '123',
code:''
},
checked: true,
rules: {
username: [{required: true, message: '请输入用户名', trigger: 'blur'}],
password: [{required: true, message: '请输入密码', trigger: 'blur'}]
password: [{required: true, message: '请输入密码', trigger: 'blur'}],
code: [{required: true, message: '请输入验证码', trigger: 'blur'}]
}
}
},
methods: {
updateVerifyCode() {
this.vcUrl = '/verifyCode?time='+new Date();
},
submitLogin() {
this.$refs.loginForm.validate((valid) => {
if (valid) {
......@@ -54,10 +65,11 @@
window.sessionStorage.setItem("user", JSON.stringify(resp.obj));
let path = this.$route.query.redirect;
this.$router.replace((path == '/' || path == undefined) ? '/home' : path);
}else{
this.vcUrl = '/verifyCode?time='+new Date();
}
})
} else {
this.$message.error('请输入所有字段');
return false;
}
});
......@@ -88,4 +100,8 @@
text-align: left;
margin: 0px 0px 15px 0px;
}
.el-form-item__content{
display: flex;
align-items: center;
}
</style>
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册