前后端分离-根据代码讲解思路

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/m0_37499059/article/details/83244008

1.前面写过前后端分离相关文章

第一篇-为什么要前后端分离 https://blog.csdn.net/m0_37499059/article/details/82082534
第二篇-感受一下前后端分离 https://blog.csdn.net/m0_37499059/article/details/82082825


源码下载: https://github.com/chenxingxing6/cxxfast
在这里插入图片描述

2.根据代码讲解思路

用户登录时,生成一个token,并给token设一个过期时间,保存在数据库里(redis里)。每次请求api时都带上该token,然后对token进行校验,是不是该用户的,并且时间有没有过期。这里的token最后是放在请求头里面,然后设置全局范围起作用,不需要每次还关心要自己传token.

2.1 token什么时候生成(用户授权认证成功后)

在这里插入图片描述

token用什么算法生成,看自己怎么实现了

	@Override
	public R createToken(long userId) {
		//生成一个token
		String token = TokenGenerator.generateValue();
		//当前时间
		Date now = new Date();
		//过期时间
		Date expireTime = new Date(now.getTime() + EXPIRE * 1000);
		//判断是否生成过token
		SysUserToken tokenEntity = sysUserTokenDao.selectById(userId);
		if(tokenEntity == null){
			tokenEntity = new SysUserToken();
			tokenEntity.setUserId(userId);
			tokenEntity.setToken(token);
			tokenEntity.setUpdateTime(now);
			tokenEntity.setExpireTime(expireTime);
			//保存token
			sysUserTokenDao.insert(tokenEntity);
		}else{
			tokenEntity.setToken(token);
			tokenEntity.setUpdateTime(now);
			tokenEntity.setExpireTime(expireTime);
			//更新token
			sysUserTokenDao.updateById(tokenEntity);
		}
		R r = R.ok().put("token", token).put("expire", EXPIRE);
		return r;
	}

生成token

package cn.jeefast.common.oauth2;
import java.security.MessageDigest;
import java.util.UUID;
import cn.jeefast.common.exception.RRException;

/**
 * 生成token
 */
public class TokenGenerator {
    public static String generateValue() {
        return generateValue(UUID.randomUUID().toString());
    }
    private static final char[] hexCode = "0123456789abcdef".toCharArray();
    public static String toHexString(byte[] data) {
        if(data == null) {
            return null;
        }
        StringBuilder r = new StringBuilder(data.length*2);
        for ( byte b : data) {
            r.append(hexCode[(b >> 4) & 0xF]);
            r.append(hexCode[(b & 0xF)]);
        }
        return r.toString();
    }
    public static String generateValue(String param) {
        try {
            MessageDigest algorithm = MessageDigest.getInstance("MD5");
            algorithm.reset();
            algorithm.update(param.getBytes());
            byte[] messageDigest = algorithm.digest();
            return toHexString(messageDigest);
        } catch (Exception e) {
            throw new RRException("生成Token失败", e);
        }
    }
}

2.2 前端登录接收到返回的消息和token,然后把token保持的本地(localstorage 存储对象)

在这里插入图片描述


2.3然后设置全局js,获取token,并设置ajax请求是head都统一带上token

common.js

//请求前缀
var baseURL = "/project/";

//登录token
var token = localStorage.getItem("token");
if(token == 'null'){
    parent.location.href = baseURL + 'login.html';
}

//jquery全局配置
$.ajaxSetup({
	dataType: "json",
	cache: false,
    headers: {
        "token": token
    },
    complete: function(xhr) {
        //token过期,则跳转到登录页面
        if(xhr.responseJSON.code == 401){
            parent.location.href = baseURL + 'login.html';
        }
    }
});

//jqgrid全局配置
$.extend($.jgrid.defaults, {
    ajaxGridOptions : {
        headers: {
            "token": token
        }
    }
});

在这里插入图片描述


2.4 退出登录操作,清除token
 logout: function () {
	//删除本地token
   localStorage.removeItem("token");
   //跳转到登录页面
   location.href = baseURL + 'login.html';
}

2.5 Java对api进行拦截,除了不需要权限的,去校验token

第一种方式:用了shiro框架
在这里插入图片描述

第二种方式:写一个拦截器,对token进行校验

这里我们自己定义一个注解,如果不要授权的api,就加上改注解

在这里插入图片描述

拦截器实现

@Component
public class AuthorizationInterceptor extends HandlerInterceptorAdapter {
    @Autowired
    private TbTokenService tokenService;
    public static final String USER_KEY = "userId";
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        AuthIgnore annotation;
        if(handler instanceof HandlerMethod) {
            annotation = ((HandlerMethod) handler).getMethodAnnotation(AuthIgnore.class);
        }else{
            return true;
        }
        //如果有@IgnoreAuth注解,则不验证token
        if(annotation != null){
            return true;
        }
        //从header中获取token
        String token = request.getHeader("token");
        //如果header中不存在token,则从参数中获取token
        if(StringUtils.isBlank(token)){
            token = request.getParameter("token");
        }
        //token为空
        if(StringUtils.isBlank(token)){
            throw new RRException("token不能为空");
        }
        //查询token信息
        TbToken tokenEntity = tokenService.queryByToken(token);
        if(tokenEntity == null || tokenEntity.getExpireTime().getTime() < System.currentTimeMillis()){
            throw new RRException("token失效,请重新登录");
        }
        //设置userId到request里,后续根据userId,获取用户信息
        request.setAttribute(USER_KEY, tokenEntity.getUserId());
        return true;
    }
}

注解:

import java.lang.annotation.*;
/**
 * api接口,忽略Token验证
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AuthIgnore {

}

总结

其实也很简单嘛,就后台提供restful接口,我前端去请求,然后解析json,绚烂我们的页面。但是这个接口肯定要有权限吧,不能让每个人都调的到,所以我们要进行认证,那我们根据用户信息,生成一个有过期时间的唯一的token,每次请求都带上,后台对token统一进行校验,如果是正确的进放行。

猜你喜欢

转载自blog.csdn.net/m0_37499059/article/details/83244008