亚马逊电商数据自动化管理接口平台Springboot+SpringSecurity链接vue+vite

亚马逊电商数据自动化管理接口平台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()
},
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值