vue前后端分离,做普通的登录拦截(未登录:返回一个自定义Exception;放开白名单:通过给方法加上自定义注解,在拦截器中查看过来的方法是否有该注解,有则放开拦截)
1.写一个登录页面
<template>
<div>
<el-form :model="user" :rules="rules" ref="ruleForm" label-width="80px" class="demo-ruleForm" style="margin-left: 35%;margin-top: 5%">
<el-form-item label="账户" prop="name">
<el-input v-model="user.name" style="width: 300px"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input v-model="user.password" style="width: 300px"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit" style="margin-left: 50px;">登录</el-button>
<!--如果在index.js中,不配置 mode:'history',去掉访问请求中的"#",就需要在前边加一个#-->
<!--<el-link href="#/register" type="primary" style="margin-left: 30px;">注册</el-link>-->
<el-link href="/regiterUser" type="primary" style="margin-left: 30px;">注册</el-link>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
name: 'Loogin',
data(){
//验证用户名不能为空
//checkName与rule中定义的必须保持一致1
var checkName = (rule, value, callback) => {
//alert(this.user.name)
if (value === '') {
callback(new Error('请输入账号'));
}
};
var validatePass = (rule, value, callback) => {
if (value === '') {
callback(new Error('请输入密码'));
}
};
return {
user: {
password: '',
name: ''
},
/*rules与form中的:rules="rules"保持一致*/
rules: {
password: [
{ validator: validatePass, trigger: 'blur' }
],
name: [
{ validator: checkName, trigger: 'blur' }
]
}
};
},
methods:{
onSubmit(){
var self = this;
this.$axios.post('http://localhost:8089/user/loginUser.do',this.$qs.stringify(this.user)).then(function (response) {
console.log(response)
if (response.data.code===1000){
//跳转到登录页面
self.$router.push("/indexPage")
}else{
alert(response.data.data);
// self.$router.push("/")
}
})
}
}
}
</script>
<style scoped>
</style>
2.写一个注册页面,表单验证【因为涉及到MD5加盐加密,先注册几条数据】
<template>
<div>
<el-form :model="user" status-icon :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm" style="margin-left: 35%;margin-top: 5%">
<el-form-item label="账号" prop="name">
<el-input v-model.number="user.name" style="width: 300px"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input type="password" v-model="user.password" autocomplete="off" style="width: 300px"></el-input>
</el-form-item>
<el-form-item label="确认密码" prop="checkPass">
<el-input type="password" v-model="user.checkPass" autocomplete="off" style="width: 300px"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('ruleForm')" style="margin-left: 50px;">提交</el-button>
<el-button @click="resetForm('ruleForm')" style="margin-left: 30px;">重置</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
name: 'regiterUser',
data() {
var checkName = (rule, value, callback) => {
if (value === '') {
callback(new Error('请输入账号'));
}else{
//查询账号是否存在
this.$axios.post('http://localhost:8089/user/checkUserByName.do',this.$qs.stringify({"name":this.user.name})).then(function (response) {
if (response.data.code===1000){
callback();
}
else{
callback(new Error('账号已存在'));
}
})
}
};
var validatePass = (rule, value, callback) => {
if (value === '') {
callback(new Error('请输入密码'));
} else {
if (this.user.checkPass !== '') {
this.$refs.ruleForm.validateField('checkPass');
}
callback();
}
};
var validatePass2 = (rule, value, callback) => {
if (value === '') {
callback(new Error('请再次输入密码'));
} else if (value !== this.user.password) {
callback(new Error('两次输入密码不一致!'));
} else {
callback();
}
};
return {
user: {
password: '',
checkPass: '',
name: ''
},
rules: {
password: [
{ validator: validatePass, trigger: 'blur' }
],
checkPass: [
{ validator: validatePass2, trigger: 'blur' }
],
name: [
{ validator: checkName, trigger: 'blur' }
]
}
};
},
methods: {
submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
alert('submit!');
var self = this;
this.$axios.post('http://localhost:8089/user/registerUser.do',this.$qs.stringify(this.user)).then(function (response) {
if (response.data.code===1000){
//跳转到登录页面
self.$router.push("/")
}
})
} else {
console.log('error submit!!');
return false;
}
});
},
resetForm(formName) {
this.$refs[formName].resetFields();
}
}
}
</script>
<style scoped>
</style>
3.正式开始登录拦截代码
1)在spring-mvc-controller.xml配置拦截器
<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<!-- 按照以往方式,在这里配置不需要拦截的,这里换通过注解来查询不需要拦截的方法,然后放开,此处就不需要了-->
<!-- 代表哪些方法不用拦截 (可以配置多个)-->
<!-- <mvc:exclude-mapping path="/user/checkUserByName.do"/>
<mvc:exclude-mapping path="/user/registerUser.do"/>
<mvc:exclude-mapping path="/user/loginUser.do"/>-->
<bean class="com.fh.intercetpor.LoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
2)自定义一个注解类【如果不拦截的方法,就被该自定义的注解修饰,在interceptor中判断,如果访问的方法有该注解,则放开拦截】
@Documented //它的作用是能够将注解中的元素包含到 Javadoc 中去
@Target(ElementType.METHOD) //表示我们的注解作用的范围就比较具体了,可以是类,方法,方法参数变量
@Retention(RetentionPolicy.RUNTIME)//它表示注解存在阶段是保留在源码(编译期),注解会在class字节码文件中存在,在运行时可以通过反射获取到
public @interface Ignore {
}
例如:
/**
* 通过name查询用户是否存在
* @param name
* @return
*/
@Ignore
@RequestMapping("checkUserByName")
public ResponseServer checkUserByName(String name){
return userService.checkUserByName(name);
}
/**
* 注册用户
* @param user
* @return
*/
@Ignore
@RequestMapping("registerUser")
public ResponseServer registerUser(User user){
return userService.registerUser(user);
}
3)写一个异常类,当用户,没有登录时,就throw自定义的异常
/**
* 写一个异常类,运行时异常,也可以是其他的异常,根据情况需要
*/
public class MyException extends RuntimeException {
}
写一个全局的异常类
因为是controller的注解,所以需要在controller的配置文件中,conpent-scan中配置对该异常的文件扫描
/**
* 配置一个全局的异常
* 把需要配置的异常在这里进行配置,当抛异常时候,返回前台一个error,前台就可以根据这个返回的code进行判断
* @RestController 写上以后,下边的方法就不需要写ReponseBody
*
* 要使注解生效,在spring-mvc-controller.xml文件需要配置
*/
@RestControllerAdvice
public class ClobleHandlerException {
/**
* 自定义的异常
* @param e
* @return
*/
@ExceptionHandler(MyException.class)
public ResponseServer myExceptionHandler(MyException e){
e.printStackTrace();
return ResponseServer.errorMethod();
}
/**
* 抛所有的异常
* @param e
* @return
*/
@ExceptionHandler(Exception.class)
public ResponseServer exceptionHandler(Exception e){
e.printStackTrace();
return ResponseServer.errorMethod();
}
}
<!--Exception中,有controller的注解,使其生效-->
<context:component-scan base-package="com.fh.exception"/>
4)写拦截器
/**
* 登录拦截,利用ignore来做的,不需要在spring-mvc.xml中配置
*/
public class LoginInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//1.在这里设置全局的跨域问题,所以在controller层的跨域注解也可以不用写了
//处理跨域问题
response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN,"http://localhost:8081");
//处理客户端传过来的自定义头信息【自定义:从前台地址栏查看,传过来的信息是何种信息,然后添加上,才可以放开拦截,否则就会拦截】
response.addHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS,"x-auth,content-type,mtoken");
//处理客户端发过来的put delete【自定义的,从前台发送请求的路径中查看,需要添加何种请求,然后添加上,才可以放开拦截,否则就会拦截】
response.addHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS,"PUT,POST,DELETE,GET");
//跨域,如果登录拦截时候,访问不到后台数据,浏览器就会报:No 'Access-Control-Allow-Origin' header is present on the requested ,加上这个就不会报了
response.addHeader("Access-Control-Allow-Credentials","true");
//2.判断访问的请求是否是:注解@Ignore修饰的方法
//获取方法
HandlerMethod handlerMethod = (HandlerMethod)handler;
Method method = handlerMethod.getMethod();
//判断该方法是否有@Ignore注解
if(method.isAnnotationPresent(Ignore.class)){
//如果有,放开
return true;
}
//获取session,查看是否有用户登录
User user = (User) request.getSession().getAttribute(Const.LOGIN_SESSION_USER);
if(user == null){
//证明没有有用户登录,则抛自定义的异常
throw new MyException();
}
return true;
}
}
vue页面配置:
main.js
// 把coookie发送到服务器
axios.defaults.withCredentials = true
// 定义一个请求拦截器
axios.interceptors.request.use(function (config) {
console.log(config)
return config
})
// 定义一个相应拦截器
axios.interceptors.response.use(function (config) {
console.log(config)
// 错误的code=2000,如果=2000,则证明没有登录,跳到登录页面
if (config.data.code === 2000) {
location.href = '/'
}
return config
})