亚马逊电商数据自动化管理接口平台Springboot+SpringSecurity链接vue+vite
重要说明
- 本文章为亚马逊系列其中的一篇,具体详见 主页 中亚马逊分类
- 该系列项目均为【CSDN轻夏】原创,未经允许禁止转载
- 如有疑问请添加qq群聊302493982学习咨询
本文参考 https://www.bilibili.com/video/BV1ff4y1M7XK
文章目录
后端配置
SecurityConfig
package com.rss.server.config.security;
import com.rss.server.config.security.component.JwtAuthencationTokenFilter;
import com.rss.server.config.security.component.RestAuthorizationEntryPoint;
import com.rss.server.config.security.component.RestfulAccessDeniedHandler;
import com.rss.server.pojo.Admin;
import com.rss.server.service.IAdminService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
/**
* Security配置类
*/
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private IAdminService adminService;
@Autowired
private RestAuthorizationEntryPoint restAuthorizationEntryPoint;
@Autowired
private RestfulAccessDeniedHandler restfulAccessDeniedHandler;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());
}
@Override
public void configure(WebSecurity web) {
web.ignoring().antMatchers(
"/login",
"/logout",
"/css/**",
"/js/**",
"/index.html",
"favicon.ico",
"/doc.html",
"/webjars/**",
"/swagger-resources/**",
"/v2/api-docs/**",
"/captcha",
"/ws/**"
);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
//使用JWT,不需要csrf
http.csrf()
.disable()
//基于token,不需要session
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/login").permitAll()
//所有请求都要求认证
.anyRequest()
.authenticated()
.and()
//禁用缓存
.headers()
.cacheControl();
//添加jwt 登录授权过滤器
http.addFilterBefore(jwtAuthencationTokenFilter(), UsernamePasswordAuthenticationFilter.class);
//添加自定义未授权和未登录结果返回
http.exceptionHandling()
.accessDeniedHandler(restfulAccessDeniedHandler)
.authenticationEntryPoint(restAuthorizationEntryPoint);
}
@Override
@Bean
public UserDetailsService userDetailsService() {
return username -> {
Admin admin = adminService.getAdminByUserName(username);
if (null != admin) {
return admin;
}
throw new UsernameNotFoundException("用户名或密码不正确");
};
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public JwtAuthencationTokenFilter jwtAuthencationTokenFilter() {
return new JwtAuthencationTokenFilter();
}
}
CustomUrlDecisionManager
package com.rss.server.config.security.component;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Component;
import java.util.Collection;
/**
* 权限控制
* 判断用户角色
*
*/
@Component
public class CustomUrlDecisionManager implements AccessDecisionManager {
@Override
public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
for (ConfigAttribute configAttribute : configAttributes) {
//当前url所需角色
String needRole = configAttribute.getAttribute();
//判断角色是否登录即可访问的角色,此角色在CustomFilter中设置
if ("ROLE_LOGIN".equals(needRole)){
//判断是否登录
if (authentication instanceof AnonymousAuthenticationToken){
throw new AccessDeniedException("尚未登录,请登录!");
}else {
return;
}
}
//判断用户角色是否为url所需角色
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
for (GrantedAuthority authority : authorities) {
if (authority.getAuthority().equals(needRole)){
return;
}
}
}
throw new AccessDeniedException("权限不足,请联系管理员!");
}
@Override
public boolean supports(ConfigAttribute attribute) {
return true;
}
@Override
public boolean supports(Class<?> clazz) {
return true;
}
}
JwtAuthencationTokenFilter
package com.rss.server.config.security.component;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* JWT登录授权过滤器
*
*/
public class JwtAuthencationTokenFilter extends OncePerRequestFilter {
@Value("${jwt.tokenHeader}")
private String tokenHeader;
@Value("${jwt.tokenHead}")
private String tokenHead;
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String authHeader = request.getHeader(tokenHeader);
//存在token
if (null != authHeader && authHeader.startsWith(tokenHead)) {
String authToken = authHeader.substring(tokenHead.length());
String username = jwtTokenUtil.getUserNameFromToken(authToken);
//token存在用户名但未登录
if (null != username && null == SecurityContextHolder.getContext().getAuthentication()) {
//登录
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
//验证token是否有效,重新设置用户对象
if (jwtTokenUtil.validateToken(authToken, userDetails)) {
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
}
}
filterChain.doFilter(request, response);
}
}
JwtTokenUtil
package com.rss.server.config.security.component;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* JwtToken工具类
*
*/
@Component
public class JwtTokenUtil {
private static final String CLAIM_KEY_USERNAME = "sub";
private static final String CLAIM_KEY_CREATED = "created";
@Value("${jwt.secret}")
private String secret;
@Value("${jwt.expiration}")
private Long expiration;
/**
* 根据用户信息生成token
*
* @param userDetails
* @return
*/
public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
claims.put(CLAIM_KEY_USERNAME, userDetails.getUsername());
claims.put(CLAIM_KEY_CREATED, new Date());
return generateToken(claims);
}
/**
* 从token中获取登录用户名
* @param token
* @return
*/
public String getUserNameFromToken(String token){
String username;
try {
Claims claims = getClaimsFormToken(token);
username = claims.getSubject();
} catch (Exception e) {
username = null;
}
return username;
}
/**
* 验证token是否有效
* @param token
* @param userDetails
* @return
*/
public boolean validateToken(String token,UserDetails userDetails){
String username = getUserNameFromToken(token);
return username.equals(userDetails.getUsername()) && !isTokenExpired(token);
}
/**
* 判断token是否可以被刷新
* @param token
* @return
*/
public boolean canRefresh(String token){
return !isTokenExpired(token);
}
/**
* 刷新token
* @param token
* @return
*/
public String refreshToken(String token){
Claims claims = getClaimsFormToken(token);
claims.put(CLAIM_KEY_CREATED,new Date());
return generateToken(claims);
}
/**
* 判断token是否失效
* @param token
* @return
*/
private boolean isTokenExpired(String token) {
Date expireDate = getExpiredDateFromToken(token);
return expireDate.before(new Date());
}
/**
* 从token中获取过期时间
* @param token
* @return
*/
private Date getExpiredDateFromToken(String token) {
Claims claims = getClaimsFormToken(token);
return claims.getExpiration();
}
/**
* 从token中获取荷载
* @param token
* @return
*/
private Claims getClaimsFormToken(String token) {
Claims claims = null;
try {
claims = Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
} catch (Exception e) {
e.printStackTrace();
}
return claims;
}
/**
* 根据荷载生成JWT TOKEN
*
* @param claims
* @return
*/
private String generateToken(Map<String, Object> claims) {
return Jwts.builder()
.setClaims(claims)
.setExpiration(generateExpirationDate())
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
}
/**
* 生成token失效时间
*
* @return
*/
private Date generateExpirationDate() {
return new Date(System.currentTimeMillis() + expiration * 1000);
}
}
RestAuthorizationEntryPoint
package com.rss.server.config.security.component;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.rss.server.pojo.RespBean;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* 当未登录或者token失效时访问接口时,自定义的返回结果
*/
@Component
public class RestAuthorizationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json");
PrintWriter out = response.getWriter();
RespBean bean = RespBean.error("尚未登录,请登录!");
bean.setCode(401);
out.write(new ObjectMapper().writeValueAsString(bean));
out.flush();
out.close();
}
}
RestfulAccessDeniedHandler
package com.rss.server.config.security.component;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.rss.server.pojo.RespBean;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* 当访问接口没有权限时,自定义返回结果
*
*/
@Component
public class RestfulAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json");
PrintWriter out = response.getWriter();
RespBean bean = RespBean.error("权限不足,请联系管理员!");
bean.setCode(403);
out.write(new ObjectMapper().writeValueAsString(bean));
out.flush();
out.close();
}
}
JWT配置文件
jwt:
# JWT存储的请求头
tokenHeader: Authorization
# JWT 加解密使用的密钥
secret: yjxxt
# JWT的超期限时间(60*60*24)
expiration: 604800
# JWT 负载中拿到开头
tokenHead: Bearer
Swagger2Config配置类
package com.rss.server.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.ApiKey;
import springfox.documentation.service.AuthorizationScope;
import springfox.documentation.service.Contact;
import springfox.documentation.service.SecurityReference;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.ArrayList;
import java.util.List;
/**
* Swagger2配置类
*
* @author zhoubin
* @since 1.0.0
*/
@Configuration
@EnableSwagger2
public class Swagger2Config {
@Bean
public Docket createRestApi(){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.rss.server.controller"))
.paths(PathSelectors.any())
.build()
.securityContexts(securityContexts())
.securitySchemes(securitySchemes());
}
private ApiInfo apiInfo(){
return new ApiInfoBuilder()
.title("接口文档")
.description("接口文档")
.contact(new Contact("rss","http:localhost:8081/doc.html","rss@rss.com"))
.version("1.0")
.build();
}
private List<ApiKey> securitySchemes(){
//设置请求头信息
List<ApiKey> result= new ArrayList<>();
ApiKey apiKey = new ApiKey("Authorization","Authorization","Header");
result.add(apiKey);
return result;
}
private List<SecurityContext> securityContexts(){
//设置需要登录认证的路径
List<SecurityContext> result = new ArrayList<>();
result.add(getContextByPath("/hello/.*"));
return result;
}
private SecurityContext getContextByPath(String pathRegex) {
return SecurityContext.builder()
.securityReferences(defaultAuth())
.forPaths(PathSelectors.regex(pathRegex))
.build();
}
private List<SecurityReference> defaultAuth() {
List<SecurityReference> result = new ArrayList<>();
AuthorizationScope authorizationScope = new AuthorizationScope("global","accessEverything");
AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
authorizationScopes[0] = authorizationScope;
result.add(new SecurityReference("Authorization",authorizationScopes));
return result;
}
}
登录授权
LoginController
package com.rss.server.controller;
import com.rss.server.pojo.Admin;
import com.rss.server.pojo.AdminLoginParam;
import com.rss.server.pojo.RespBean;
import com.rss.server.service.IAdminService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.security.Principal;
/**
* 登录
*
* @author zhoubin
* @since 1.0.0
*/
@Api(tags = "LoginController")
@CrossOrigin(origins = "*", allowedHeaders = "*")
@RestController
public class LoginController {
@Autowired
private IAdminService adminService;
@ApiOperation(value = "登录之后返回token")
@PostMapping("/login")
public RespBean login(@RequestBody AdminLoginParam adminLoginParam, HttpServletRequest request){
return adminService.login(adminLoginParam.getUsername(),adminLoginParam.getPassword(),adminLoginParam.getCode(),request);
}
@ApiOperation(value = "获取当前登录用户的信息")
@GetMapping("/admin/info")
public Admin getAdminInfo(Principal principal){
System.out.println("---------");
if (null==principal){
return null;
}
String username = principal.getName();
Admin admin = adminService.getAdminByUserName(username);
admin.setPassword(null);
// admin.setRoles(adminService.getRoles(admin.getId()));
System.out.println(admin);
return admin;
}
@ApiOperation(value = "退出登录")
@PostMapping("/logout")
public RespBean logout(Principal principal){
if (null==principal){
return RespBean.success("注销成功!");
}
refresh(principal);
return RespBean.success("注销成功!");
}
@ApiOperation(value = "刷新Token")
@GetMapping("/refresh")
public void refresh(Principal principal){
if (null==principal){
return;
}
adminService.refreshToken(principal.getName());
}
}
验证码授权
验证码配置类
CaptchaConfig
package com.rss.server.config;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Properties;
/**
* 验证码配置类
*
* @author zhoubin
* @since 1.0.0
*/
@Configuration
public class CaptchaConfig {
@Bean
public DefaultKaptcha defaultKaptcha(){
//验证码生成器
DefaultKaptcha defaultKaptcha=new DefaultKaptcha();
//配置
Properties properties = new Properties();
//是否有边框
properties.setProperty("kaptcha.border", "yes");
//设置边框颜色
properties.setProperty("kaptcha.border.color", "105,179,90");
//边框粗细度,默认为1
// properties.setProperty("kaptcha.border.thickness","1");
//验证码
properties.setProperty("kaptcha.session.key","code");
//验证码文本字符颜色 默认为黑色
properties.setProperty("kaptcha.textproducer.font.color", "blue");
//设置字体样式
properties.setProperty("kaptcha.textproducer.font.names", "宋体,楷体,微软雅黑");
//字体大小,默认40
properties.setProperty("kaptcha.textproducer.font.size", "30");
//验证码文本字符内容范围 默认为abced2345678gfynmnpwx
// properties.setProperty("kaptcha.textproducer.char.string", "");
//字符长度,默认为5
properties.setProperty("kaptcha.textproducer.char.length", "4");
//字符间距 默认为2
properties.setProperty("kaptcha.textproducer.char.space", "4");
//验证码图片宽度 默认为200
properties.setProperty("kaptcha.image.width", "100");
//验证码图片高度 默认为40
properties.setProperty("kaptcha.image.height", "40");
Config config = new Config(properties);
defaultKaptcha.setConfig(config);
return defaultKaptcha;
}
}
CaptchaController
package com.rss.server.controller;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.IOException;
/**
* 验证码
*
* @author zhoubin
* @since 1.0.0
*/
@RestController
public class CaptchaController {
@Autowired
private DefaultKaptcha defaultKaptcha;
@ApiOperation(value = "验证码")
@GetMapping(value = "/captcha",produces = "image/jpeg")
public void captcha(HttpServletRequest request, HttpServletResponse response){
// 定义response输出类型为image/jpeg类型
response.setDateHeader("Expires", 0);
// Set standard HTTP/1.1 no-cache headers.
response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
// Set IE extended HTTP/1.1 no-cache headers (use addHeader).
response.addHeader("Cache-Control", "post-check=0, pre-check=0");
// Set standard HTTP/1.0 no-cache header.
response.setHeader("Pragma", "no-cache");
// return a jpeg
response.setContentType("image/jpeg");
//获取验证码文本内容
String text = defaultKaptcha.createText();
System.out.println("验证码内容:"+text);
//将验证码文本内容放入session
request.getSession().setAttribute("captcha",text);
//根据文本验证码内容创建图形验证码
BufferedImage image = defaultKaptcha.createImage(text);
ServletOutputStream outputStream = null;
try {
outputStream = response.getOutputStream();
//输出流输出图片,格式为jpg
ImageIO.write(image,"jpg",outputStream);
outputStream.flush();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (null!=outputStream){
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
前端配置
vite.config.js配置
vue和vite的路由配置不一样,下面展示的是vite
在项目总目录下创建vite.config.js
import vue from '@vitejs/plugin-vue'
export default {
base: './',
plugins: [vue()],
optimizeDeps: {
include: ['schart.js']
},
server: {
port: 3000, //前端的地址
proxy: {
'/api': { //把前端127.0.0.1:3000/api转换为http://127.0.0.1:8081/
//注意在浏览器f12里面仍然显示127.0.0.1:3000/api,但结果是后端结果
//如果想访问前端127.0.0.1:3000中的东西,可以不加api即可,例如127.0.0.1:3000/index.html
target: 'http://127.0.0.1:8081/', // 后端的地址
changeOrigin: true, //访问的时候把Origin换掉,防止跨域访问禁止
rewrite:(path) => path.replace(/^\/api/, '') //转换的时候把api去掉
}
}
},
}
api配置
设置响应拦截器和请求拦截器
import axios from "axios";
import { Message } from 'element-ui'
import router from "../router";
//请求拦截器
axios.interceptors.request.use(config=> {
//如果存在,请求token
if (window.sessionStorage.getItem("tokenStr")) {
config.headers['Authorization'] = window.sessionStorage.getItem("tokenStr");
}
return config;
}, error => {
console.log(error);
})
//响应拦截器
axios.interceptors.response.use(success=> {
console.log(success.data)
if (success.status && success.status == 200) {
if (success.data.code == 500 || success.data.code == 401 || success.data.code == 403) {
Message.error({message:success.data.message});
return;
}
if (success.data.message) {
Message.success({message:success.data.message});
}
}
return success.data;
}, error => {
console.log(error)
if (error.response.code == 504 || error.response.code == 504) {
Message.error({message:"服务器挂了"});
} else if (error.response.code == 403) {
Message.error({message:"权限不足!"});
} else if (error.response.code == 401) {
Message.error({message:"尚未登录!"});
router.replace("/login")
} else {
if (error.response.data.message) {
Message.error({message:success.data.message});
} else {
Message.error({message:"未知错误!"});
}
}
})
let base = "/api" //和前面vite.config.js对应
//传送json格式的post请求
export const postRequest = (url, params) => {
return axios({
method : "post",
url : `${base}${url}`,
data : params
})
}
export const getRequest = (url, params) => {
return axios({
method : "get",
url : `${base}${url}`,
data : params
})
}
export const deleteRequest = (url, params) => {
return axios({
method : "delete",
url : `${base}${url}`,
data : params
})
}
main.js 配置
在main.js里面设置路由跳转,如果没有token就跳转到登录页面
router.beforeEach((to, from, next) => {
if (to.path === "/login") {
return next();
}
if (!window.sessionStorage.getItem("tokenStr")) {
return next("/login")
} else {
userInfo(store);
next();
}
});
表单登录
<el-form :model="form" ref="loginFormRef" :status-icon="true">
<el-form-item prop="username">
<el-input prefix-icon="el-icon-user-solid" placeholder="账号" v-model="form.username"></el-input>
</el-form-item>
<el-form-item prop="password">
<el-input type="password" prefix-icon="el-icon-lock" placeholder="密码" v-model="form.password"></el-input>
</el-form-item>
<el-form-item prop="code">
<el-row :gutter="20">
<el-col :span="14">
<el-input prefix-icon="el-icon-cloudy" placeholder="验证码" v-model="form.code"></el-input>
</el-col>
<el-col :span="10" style="height: 100%;">
<img :src="vcUrl" @click="updateVerifyCode" class="code_img"/>
</el-col>
</el-row>
</el-form-item>
<el-form-item class="btns">
<el-button type="primary" @click="submitLogin">登录</el-button>
<el-button type="info" @click="resetLoginForm">重置</el-button>
</el-form-item>
</el-form>
form:{
username:"",
password:"",
code:""
},
验证登录
submitLogin () {
this.$refs.loginFormRef.validate(valid => {
// console.log(valid)
if (valid) {
postRequest("/login", this.form).then(resp=> {
if (resp) {
//存储用户token
const tokenStr = resp['obj']['tokenHead'] + resp['obj']['token'];
window.sessionStorage.setItem('tokenStr', tokenStr);
//跳转首页
this.$router.replace("/inner")
}
})
}
})
},
// 点击重置按钮 重置表单
resetLoginForm () {
// console.log(this)
this.$refs.loginFormRef.resetFields()
},