前后端分离 JWT令牌

pom依赖

        <!--  JWT  -->
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.18.3</version>
        </dependency>
        <!--SpringBoot Security-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

JWT工具类

package com.auo.Utils;


import com.auo.Pojo.UacUser;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;


/**
 * @Program: configplus
 * @Description: Token 工具类
 * @Author: YangHuHC
 * @Create: 2023/7/27 9:50
 */
@Slf4j
public class TokenUtils {

    private final static String tokenHeader = "Authorization";


    /**
     * 过期时间2个小时,
     * TODO 正式运行时修改为15分钟
     */
    private static final long EXPIRE_TIME = 2 * 60 * 60 * 1000;
    /**
     * token私钥
     */
    private static final String TOKEN_SECRET = "auo";

    /**
     * 校验 token是否正确
     *
     * @param token  密钥
     * @return 是否正确
     */
    public static boolean verify(String token, String username,String dept,String userId) throws Exception {
        try {
            Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
            JWTVerifier verifier = JWT.require(algorithm)
                    .withClaim("username", username)
                    .withClaim("dept", dept)
                    .withClaim("userId", userId)
                    .build();
            verifier.verify(token);
            log.info("token is valid");
            return true;
        } catch (TokenExpiredException e) {
            throw new TokenExpiredException("登录过期,请重新登录");
        } catch (Exception e) {
            log.info("token is invalid {}", e.getMessage());
            throw new Exception(e.getMessage());
        }
    }
    /**
     * 获得token中的信息无需secret解密也能获得
     *
     * @return token中包含的用户登录信息
     */
    public static UacUser getUacUser(String token) {
        try {
            UacUser uacUser = new UacUser();
            DecodedJWT jwt = JWT.decode(token);
            uacUser.setDeptNo(jwt.getClaim("dept").asString());
            uacUser.setName(jwt.getClaim("username").asString());
            uacUser.setId(jwt.getClaim("userId").asString());

            return uacUser;
        } catch (JWTDecodeException e) {
            log.error("error:{}", e.getMessage());
            throw new JWTDecodeException(e.getMessage());
        }
    }


    /**
     * 获得token中的信息无需secret解密也能获得
     *
     * @return token中包含的用户登录信息
     */
    public static String getUsername(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim("username").asString();
        } catch (JWTDecodeException e) {
            log.error("error:{}", e.getMessage());
            throw new JWTDecodeException(e.getMessage());
        }
    }
    /**
     * 获得token中的信息无需secret解密也能获得
     *
     * @return token中包含的用户登录信息
     */
    public static String getUserId(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim("userId").asString();
        } catch (JWTDecodeException e) {
            log.error("error:{}", e.getMessage());
            throw new JWTDecodeException(e.getMessage());
        }
    }
    /**
     * 获得token中的信息无需secret解密也能获得
     *
     * @return token中包含的用户登录信息
     */
    public static String getUserDept(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim("dept").asString();
        } catch (JWTDecodeException e) {
            log.error("error:{}", e.getMessage());
            throw new JWTDecodeException(e.getMessage());
        }
    }

    /**
     * 生成签名,15min后过期
     *
     * @param username 用户名
     * @return 加密的token
     */
    public static String sign(String username,String dept,String userId) throws Exception {

        try {
            username = username.toLowerCase();
            Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
            Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
            return JWT.create()
                    .withClaim("username", username)
                    .withClaim("dept", dept)
                    .withClaim("userId", userId)
                    .withExpiresAt(date)
                    .sign(algorithm);

        } catch (Exception e) {
            log.error("error:", e);
            throw new Exception(e.getMessage());
        }

    }
    /**
     * 获取请求token
     *
     * @param request
     * @return token
     */
    public static String getToken(HttpServletRequest request) {
        String requestHeader = request.getHeader(tokenHeader);
        String token = "";
        if (requestHeader != null && requestHeader.startsWith("Bearer ")) {
            token = requestHeader.substring(7);
        }
        return token;
    }
}

请求拦截类

package com.auo.config;

import com.auo.Pojo.UacUser;
import com.auo.Utils.TokenUtils;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
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;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
/**
 * 该类为接受authKey的类,若访问时带上UAC的authKey会自动登陆并跳转至首页
 * 若该系统挂在一个使用uac验证的系统时,只要在请求时带上authKey就不需要二次登陆
 * zhi.li 2021.04.16
 */

@Component
public class AuthKeyFilter extends OncePerRequestFilter {

    private final Logger LOGGER = LoggerFactory.getLogger(AuthKeyFilter.class);

    //前台的首页地址
    @Value("${index-url}")
    private String indexUrl;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        //获取Authentication对象
        //Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        //获取token令牌
        String token = TokenUtils.getToken(request);
        if (!StringUtils.isEmpty(token)) {
            boolean tokenPass = false;
            try {
                UacUser uacUser = TokenUtils.getUacUser(token);
                //校验令牌
                if (TokenUtils.verify(token,uacUser.getName(),uacUser.getDeptNo(),uacUser.getId())){
                    List<GrantedAuthority> authorities = new ArrayList<>();
                    authorities.add(new SimpleGrantedAuthority("user"));
                    UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(uacUser.getId(), uacUser, authorities);
                    SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
                    tokenPass = true;
                }
            } catch (TokenExpiredException e) {
                response.setStatus(HttpStatus.BAD_REQUEST.value());
                response.setCharacterEncoding(StandardCharsets.UTF_8.name());
                response.getWriter().write("token expire");
            } catch (SignatureVerificationException e) {
                response.setStatus(HttpStatus.BAD_REQUEST.value());
                response.setCharacterEncoding(StandardCharsets.UTF_8.name());
                response.getWriter().write("sign invalid");
            } catch (Exception e) {
                LOGGER.error("AuthKeyFilter  doFilterInternal Exception  {}",e.toString());
                response.setStatus(HttpStatus.BAD_REQUEST.value());
                response.setCharacterEncoding(StandardCharsets.UTF_8.name());
                response.getWriter().write("token error");
            }
            if (!tokenPass) {
                return;
            }
        }
        filterChain.doFilter(request, response);
    }
}

spring security核心配置类 配置过滤器

package com.auo.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private final UserDetailsService userDetailsService;

    private final AuthKeyFilter authKeyFilter;

    public SecurityConfig(UserDetailsService userDetailsService, AuthKeyFilter authKeyFilter) {
        this.userDetailsService = userDetailsService;
        this.authKeyFilter = authKeyFilter;
    }

    @Override
    public UserDetailsService userDetailsService() {
        return userDetailsService;
    }

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity
                .csrf().disable().cors().and().addFilterBefore(authKeyFilter, UsernamePasswordAuthenticationFilter.class)
                .authorizeRequests()
                .antMatchers("/login/info").authenticated()
                .antMatchers("/login/**").permitAll()
                .antMatchers("/api/**").permitAll();
                
    }
        //禁用session
        httpSecurity.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}

判断是否登录 tempPage为主页面 /index 跳转主页面

    @GetMapping("/oneData/checkLoginStatus")
    public void checkLoginStatus(HttpServletRequest request, HttpServletResponse response) throws IOException {
        LOGGER.info("PostMapping /login/checkLoginStatus start");
        try {
            String authkey = request.getParameter("authkey");
            if (StringUtil.isNotEmpty(authkey)) {
                UacClientBean uacClientBean = new UacClientBean();
                uacClientBean.initial();
                auo.cim.uac.cli.bean.UacAuthority authority = uacClientBean.getFunctions("US", authkey);
                if (!authority.isPass()){
                    throw new Exception("login error");
                }
                LOGGER.info("authority : {},{},{}",authority.getUserName(),authority.getInputAccount(),authority.getDeptNo());
                UacUser uacUser = new UacUser();
                uacUser.setName(authority.getUserName());
                uacUser.setId(authority.getInputAccount());
                uacUser.setDeptNo(authority.getDeptNo());
                List<GrantedAuthority> authorities = new ArrayList<>();
                authorities.add(new SimpleGrantedAuthority("user"));
                Authentication token = new UsernamePasswordAuthenticationToken(authority.getInputAccount(), uacUser, authorities);
                SecurityContextHolder.getContext().setAuthentication(token);
                //创建令牌
                String jwt = TokenUtils.sign(uacUser.getName(), uacUser.getDeptNo(),uacUser.getId());
                LOGGER.info("jwt: {}",jwt);
                String queryString = request.getQueryString();
                String[] queryArr = queryString.split("&");
                StringBuilder urlBuild = new StringBuilder();
                for (String query : queryArr) {
                    if (!query.contains("tempPage")) {
                        urlBuild.append("&").append(URLEncoder.encode(query, "UTF-8"));
                    }
                }
                urlBuild.append("&token=").append(jwt);
                urlBuild.deleteCharAt(0);
                response.sendRedirect( indexUrl + "?" + urlBuild.toString());
                LOGGER.info("/login/checkLoginStatus sendRedirect success, token:{}",urlBuild.toString());
            }
        } catch (Exception e) {
            LOGGER.error("", e);
            //ExceptionHandler(request, response, tempPage, session);
        }
    }

前端请求拦截

main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import * as echarts from 'echarts'
import './errorSolve'
import ElementUI from 'element-ui';
import 'babel-polyfill'
import 'element-ui/lib/theme-chalk/index.css';
import 'element-ui/lib/theme-chalk/base.css';
import "./assets/css/common.css";

// 引入 axios
import axios from 'axios'
//import echarts from 'echarts'

Vue.prototype.$echarts = echarts

Vue.directive('loadmore', {
  bind(el, binding) {
    const selectWrap = el.querySelector('.el-table__body-wrapper')
    selectWrap.addEventListener('scroll', function () {
      let sign = 3
      const scrollDistance = this.scrollHeight - this.scrollTop - this.clientHeight
      if (Math.ceil(scrollDistance) <= sign) {
        binding.value()
      }
    })
  },
})

// 挂载一个自定义属性$http
Vue.prototype.$axios = axios
// 全局配置axios请求根路径(axios.默认配置.请求根路径)
axios.defaults.headers.post['Content-Type'] = 'multipart/form-data';
axios.defaults.baseURL = window.g.ServerUrl 

const service = axios.create({
  baseURL: window.g.ServerUrl , // api的base_url
  timeout: 3000000, // 请求超时时间
  withCredentials: true
})

//请求接口携带jwt令牌
service.interceptors.request.use( 
  config => {  
      if (localStorage.getItem('token')) {  
         console.log("找到token")
            config.headers.Authorization = `Bearer ` + localStorage.getItem('token') ;
              }
              else{
                console.log("没有找到token")
                config.headers.Authorization = "" ;  
              }      
            return config;  
        },error => {    
            return Promise.reject(error) ;
  });

//响应接口异常 调用登录接口
service.interceptors.response.use(
  response => {

    console.log(response);

      return response;
  }, error => {
      if (error.response) {
          //let message = JSON.stringify(error.response.data);
          let encodeTempPage =encodeURIComponent(`${window.location.origin}/oneData/#/index`);
          
          // let encodeTempPage =encodeURIComponent(`${window.location.origin}/onedatatest/#/index`);
          let targetAddress = `${axios.defaults.baseURL}/login/uacLogin?tempPage=${encodeTempPage}`;
          let redirectPage = encodeURIComponent(window.location.href);
           targetAddress=targetAddress+`&redirectPage=${redirectPage}`;
            console.log(`targetAddress `,targetAddress);
          switch (error.response.status) {
              case 403:
                window.location.href = targetAddress;
                  break;
              case 500:
                //this.$message.error("系统异常")
                  break;
              case 400:
                console.log("token expired")
                //this.$message.error("token expired")
                window.location.href = targetAddress;
                  break;
              default:
                this.$message.error("错误状态不是403,400,500");
          }
          return error.response;
      }
  }
)
Vue.prototype.$axios = service

Vue.use(ElementUI);
Vue.config.productionTip = false

new Vue({
  router,
  render: h => h(App)
}).$mount('#app')

处理返回值 将token放入本地内存

    handleToken(){
          console.log("212123123")
          const NEW_TOKEN = this.$route.query.token;
          console.log(`token `,NEW_TOKEN)
          let NEW_ADDRESS = window.location.href;
          if(NEW_TOKEN){
            localStorage.setItem("token", NEW_TOKEN);
          if (NEW_ADDRESS.indexOf('redirectPage') !== -1) {

            let handleAddress = decodeURIComponent(NEW_ADDRESS);
            let splice1 = handleAddress.split('redirectPage=')[1];
            let splice2 = splice1.split('&')[0];
            let result = splice2;
            localStorage.setItem("token", NEW_TOKEN);
            setTimeout(() => {  
              //  window.location.href = decodeURIComponent(result);
              //  this.$router.push({ path: '/index' })
            }, 200);
          } else {

            setTimeout(() => {
              localStorage.setItem("token", NEW_TOKEN);
              this.$router.push({ path: '/index' })
            }, 200);
          }
      }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值