0%

怎么实现对登录用户访问权限的拦截

一. 自定义权限注解

package io.coderyeah.basic.annotation;

import java.lang.annotation.*;

/**
 * 自定义注解
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface PreAuthorize {
    String name();

    String sn();
}

二. 在接口方法上使用注解

/**
 * @param deptDTO 部门查询参数
 * @return Result
 */
@PreAuthorize(name = "部门列表", sn = "department:list")
@LogAnnotation(module = "部门模块", operate = "分页查询部门列表")
@ApiOperation("查询部门列表")
@PostMapping("/list")
public Result list(@RequestBody(required = false) DeptDTO deptDTO) {
    return departmentService.list(deptDTO);
}

三. 登录拦截器

package io.coderyeah.basic.interceptor;

import com.alibaba.fastjson.JSON;
import io.coderyeah.basic.annotation.PreAuthorize;
import io.coderyeah.basic.constant.Constants;
import io.coderyeah.org.mapper.EmployeeMapper;
import io.coderyeah.user.domain.LoginInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Component
public class LoginInterceptor implements HandlerInterceptor {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private EmployeeMapper employeeMapper;

    @Override
    public boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object handler) throws Exception {
        // 静态资源放行
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }

        //1.获取token
        String token = req.getHeader("token");
        //3.如果有token,通过token获取redis的登录信息
        if (token != null) {
            String loginInfo = stringRedisTemplate.opsForValue().get(Constants.LOGIN_TOKEN + token); // LoginInfo对象
            if (loginInfo != null) {//登录成功,而且没有过期
                //5.如果登录信息不为null - 放行 + 刷新过期时间[重新添加到redis]
                stringRedisTemplate.opsForValue().set(Constants.LOGIN_TOKEN + token, loginInfo, 30, TimeUnit.MINUTES);
                final LoginInfo info = JSON.parseObject(loginInfo, LoginInfo.class);
                if (info.getType() == 1) {
                    // 前端用户直接放行
                    return true;
                }
                // 后端管理员 需要判断权限
                final HandlerMethod handlerMethod = (HandlerMethod) handler;
                // 获取访问的方法上的权限注解
                final PreAuthorize p = handlerMethod.getMethodAnnotation(PreAuthorize.class);
                if (null == p) {
                    // 此方法上没有该注解直接放行 公用资源
                    return true;
                }
                // 需要判断该登录用户是否具备此接口的操作权限
                final String sn = p.sn();
                // 查询该登录用户的所有权限集合
                List<String> ownPermissions = employeeMapper.getPermissionSnByLoginInfoId(info.getId());
                if (ownPermissions.contains(sn)) {
                    // 包含该权限
                    return true;
                }
                // 没有权限返回json信息给客户端
                resp.setCharacterEncoding("UTF-8");
                resp.setContentType("application/json;charset=utf-8");
                final PrintWriter writer = resp.getWriter();
                writer.print("{\"success\":false,\"message\":\"noPermission\"}");
                writer.close();
                return false;
            }
        }
        resp.setContentType("application/json;charset=UTF-8");
        resp.getWriter().println("{\"success\":false,\"message\":\"noLogin\"}");
        return false;
    }
}

四. 查询当前登录用户的所有权限涉及到多张表

<select id="getPermissionSnByLoginInfoId" resultType="java.lang.String">
    select tp.sn
    from t_employee te
             join t_employee_role ter on te.id = ter.employee_id
             join t_role tr on ter.role_id = tr.id
             join t_role_permission trp on tr.id = trp.role_id
             join t_permission tp on tp.id = trp.permission_id
    where te.logininfo_id = #{id}
</select>

网络传输数据安全

五. 前端后置拦截器处理

//======================axios的后置拦截器【处理后台登录拦截的结果】====================//
axios.interceptors.response.use(res => {
    //后端响应的是没有登录的信息
    if (false === res.data.success && "noLogin" === res.data.message) {
        localStorage.removeItem("token");
        localStorage.removeItem("loginInfo");
        router.push({path: '/login'});
    }
    if (false === res.data.success && "noPermission" === res.data.message) {
      Message.info('您没有访问权限')
    }
    return res;
},error => {
    Promise.reject(error)
})
//======================axios的后置拦截器【处理后台登录拦截的结果】====================//
-------------本文结束感谢您的阅读-------------
you can reward me here. Thank you!

欢迎关注我的其它发布渠道