记录SpringBoot项目下token的使用

记录SpringBoot项目下token的使用
项目代码:码云链接

项目技术栈

后端

* SpringBoot + MyBatis

前端

* MiniUi + jQuery

数据库

* MySql

项目集成

一、登录成功后生成token

Tip:此处的token只是用于练习用,暂未考虑安全性
@ApiOperation("用户登录时自动添加登录记录")
    @RequestMapping(value = "/login", method = RequestMethod.POST)
    public Object login(String userJSON){
        String json = userJSON.replace("[","").replace("]","");
        User user = (User) JSONArray.parseObject(json, User.class);
        String uId = user.getUId();
        String detailId = loginDetailService.selectNewDetailId();
        LoginDetail detail = new LoginDetail(detailId, uId, new Date());
        User loginUser = loginDetailService.insertLoginDetail(detail,user);
        if(loginUser != null){
            String token = createUserToken(user.getUId(), detailId);
            return detailId.concat("-").concat(String.valueOf(loginUser.getUserLevel())).concat("-").concat(token);
        }else{
            return "fail";
        }
    }

    private String createUserToken(String uId, String detailId) {
        UserToken userToken = new UserToken();
        String tokenValue = uId.concat("xzk").concat(detailId);
        userToken.setTokenKey(uId);
        userToken.setTokenValue(tokenValue);
        userToken.setCreateTime(new Date());
        Date expireTime = new Date();
        expireTime.setTime(expireTime.getTime() + 7 * 24 * 60 * 60 * 1000);
        userToken.setExpireTime(expireTime);
        UserToken token = userTokenService.selectUserTokenByKey(uId);
        if(token == null) {
            userTokenService.insertUserToken(userToken);
        }
        else{
            userToken.setTokenValue(token.getTokenValue());
            userTokenService.updateUserToken(userToken);
        }
        return userToken.getTokenValue();
    }

二、前端保存token

在这里插入图片描述

三、token传参

$.ajax({
            url: '/user/operationByUser',
            type: 'post',
            headers : {
                "token" : getToken(loginUid)
            },
            data: { userJSON: json, uId: loginUid, detailId: detailId },
            cache: false,
            success: function (text) {
                mini.alert(text,"提示",function(){
                    if(text.indexOf('成功') >= 0) {
                        delCookie();
                        window.open('/', '_top');
                    }
                });
            },
            error: function (jqXHR, textStatus, errorThrown) {
                reLogin();
                mini.alert(jqXHR.responseText,"提示",function(){
                    CloseWindow();
                });
            }
        });

四、后端Filter

1、公共Filter,用于过滤非列表接口请求

package com.productmanage.filter;

import com.productmanage.bean.User;
import com.productmanage.bean.UserToken;
import com.productmanage.service.UserService;
import com.productmanage.service.UserTokenService;
import com.productmanage.util.PropertiesUtil;
import com.productmanage.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.annotation.PostConstruct;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;

/**
 * @Description
 * @Author xzkui
 * @Date 2021/8/24 10:12
 **/
 // 过滤器注解,名称以及需要拦截的地址
@WebFilter(filterName = "publicFilter", urlPatterns = {"/user/*", "/turnOver/*", "/product/*", "/notification/*", "/logindetail/*", "/depotitem/*"})
// 过滤器排序,值越小越靠前
@Order(1)
public class PublicFilter extends OncePerRequestFilter {

    @Autowired
    private UserService userService;

    @Autowired
    private UserTokenService userTokenService;

    private static PublicFilter publicFilter;

	// 在非controller层引用servic对象时的解决方案
    @PostConstruct
    public void init(){
        publicFilter = this;
        publicFilter.userTokenService = this.userTokenService;
        publicFilter.userService = this.userService;
    }

	// 获取免过滤接口地址
    private static String avoidFilterUrl;
    static {
        try {
            avoidFilterUrl = PropertiesUtil.getPropertiesValue("config/project.properties", "avoid-filter-url");
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
	    // 获取当前请求地址
        String requestUrl = request.getRequestURI();
        // 使用cookie存放用户信息,每个用户对应一个token
        Cookie[] cookies = request.getCookies();
        if(cookies == null || requestUrl.indexOf("ByPage") >= 0 || avoidFilterUrl.indexOf(requestUrl) >= 0){
            filterChain.doFilter(request, response);
            return ;
        }
        for(Cookie cookie : cookies){
            String cookieName = cookie.getName();
            User user = userService.selectUserById(cookieName);
            if(user != null){
                String requestToken = request.getHeader("token");
                UserToken userToken = userTokenService.selectUserTokenByKey(user.getUId());
                if(StringUtil.isNotBlank(requestToken) && userToken != null) {
                    if (requestToken.equals(userToken.getTokenValue())) {
                        if (userToken.getExpireTime() != null && userToken.getExpireTime().after(new Date())) {
                            filterChain.doFilter(request, response);
                        }
                        // token 过期
                        else {
                            response.setStatus(401);
                            response.setCharacterEncoding("UTF-8");
                            response.getWriter().write("token is expired,please login again");
                        }
                    }
                    // token 错误
                    else {
                        response.setStatus(401);
                        response.setCharacterEncoding("UTF-8");
                        response.getWriter().write("wrong token!");
                    }
                }
                else{
                    response.setStatus(401);
                    response.setCharacterEncoding("UTF-8");
                    response.getWriter().write("token is not exists!");
                }
            }
        }
    }
}

2、获取列表数据接口Filter

前端使用的是MiniUi,暂时未找到datagrid获取列表数据时将token添加到headers中,所以将列表数据的请求单独新建一个Filter类
package com.productmanage.filter;

import com.productmanage.bean.User;
import com.productmanage.bean.UserToken;
import com.productmanage.service.UserService;
import com.productmanage.service.UserTokenService;
import com.productmanage.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.annotation.PostConstruct;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;

/**
 * @Description
 * @Author xzkui
 * @Date 2021/8/24 12:20
 **/
@WebFilter(filterName = "commonListFilter", urlPatterns = "/commonListController/*")
@Order(2)
public class CommonListFilter extends OncePerRequestFilter {

    @Autowired
    private UserService userService;

    @Autowired
    private UserTokenService userTokenService;

    private static CommonListFilter commonListFilter;

    @PostConstruct
    public void init(){
        commonListFilter = this;
        commonListFilter.userTokenService = this.userTokenService;
        commonListFilter.userService = this.userService;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String token = request.getHeader("token");
        if(StringUtil.isNotBlank(token)){
             UserToken userToken = userTokenService.selectUserTokenByToken(token);
            if(userToken != null && userToken.getExpireTime().after(new Date())){
                String uId = userToken.getTokenKey();
                User user = userService.selectUserById(uId);
                if(user != null){
                    filterChain.doFilter(request, response);
                }
                // token对应用户不存在
                else{
                    response.setStatus(401);
                    response.setCharacterEncoding("UTF-8");
                    response.getWriter().write("wrong token!");
                }
            }
            // token不存在
            else{
                response.setStatus(401);
                response.setCharacterEncoding("UTF-8");
                response.getWriter().write("token is not exists!");
            }
        }
        // token为空
        else{
            response.setStatus(401);
            response.setCharacterEncoding("UTF-8");
            response.getWriter().write("token is not exists!");
        }
    }
}

3、因miniui接口请求机制,部分接口配置为免过滤

  • 新建一个配置文件:resource/config/project.properties
  • 新建一个工具类PropertiesUtil.java,用于读取配置文件
package com.productmanage.util;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

/**
 * @Description
 * @Author xzkui
 * @Date 2021/8/19 14:20
 **/
public class PropertiesUtil {
    public static String getPropertiesValue(String file, String key) throws IOException {
        String rtnVal = "";
        Properties properties = new Properties();
        InputStream inputStream = null;
        try{
            inputStream = PropertiesUtil.class.getClassLoader().getResourceAsStream(file);
            properties.load(inputStream);
            rtnVal = properties.getProperty(key);
        }
        catch (Exception e){
            e.printStackTrace();
        }
        finally {
            if(inputStream != null){
                inputStream.close();
            }
        }
        return rtnVal;
    }
}

五、Application添加注解@ServletComponentScan

package com.productmanage;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.cache.annotation.EnableCaching;

@MapperScan("com.productmanage.mapper")
@SpringBootApplication
@ServletComponentScan(basePackages = "com.productmanage.filter")
@EnableCaching
public class ProductmanagementApplication {

	public static void main(String[] args) {
		SpringApplication.run(ProductmanagementApplication.class, args);
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值