springboot 点滴(3)springboot ThreadLocal实现单机权限认证

Springboot中权限认证的基本方案:
可以对URL进行HandlerInterceptor拦截,然后权限验证。

Client登录成功后,每次发送请求时,会将token等信息存放到header中。
Server收到请求,在HandlerInterceptor中从header获取用户的信息(userId,token等),然后存入上下文context;在后面Controller中就可以从上下文context中获取用户的信息做权限认证。

  • 单机应用上下文context:
    Threadlocal,在进程内部,我们可以使用ThreadLocal传递应用上下文的方式.。

  • 分布式系统上下文context:
    需要借助以下方式实现:
    1)数据库; 2)Redis ;3)文件系统。

1 HandlerInterceptor 拦截ThreadLocal实现上下文

这里讲一下单机应用Threadlocal。
ThreadLocal不是线程,是线程变量;.ThreadLocal 是 Java中一种较为特殊的线程绑定机制.通过ThreadLocal存取的数据,总是与当前线程相关。

第1步:创建User对象:

public class User {
    public String userId;
    public String orgId;
    public String token;
}

第2步:创建ThreadLocal对象来存取User:

public class ContextManager {
    private static final ThreadLocal<User>  threadLocal=  new ThreadLocal();

    public static User getUser() {
        return threadLocal.get();
    }

    public static void addUser(User user){
        threadLocal.set(user);
    }

    public static void removeUser(){
        threadLocal.remove();
    }

    public static String  getUserId(){
        return threadLocal.get().userId;
    }

    public static String  getToken(){
        return threadLocal.get().token;
    }
}

第3步:创建HandlerInterceptor:

public class AuthInterceptor implements HandlerInterceptor {
    @Autowired
    private HttpRequest httpRequest;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("threadId:"+Thread.currentThread().getId());
        String userId = (String)request.getHeader("userId");
        String token = (String)request.getHeader("token");
        if(!StringUtils.hasLength(userId)){
            response.getWriter().println("please login");
            return false;
        }
        if(!StringUtils.hasLength(token)){
            response.getWriter().println("please login");
            return false;
        }
        //将用户相关的信息存入threadlocal中
        User user = new User();
        user.userId = userId;
        user.token = token;
        ContextManager.addUser(user);
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion:"+Thread.currentThread().getId());
        ContextManager.removeUser();
    }
}

第4步:创建WebMvcConfigurer:
Spring Boot 1.5版本:重写WebMvcConfigurerAdapter的方法来添加自定义拦截器。
SpringBoot 2.0 版本后,该类被标记为@Deprecated(弃用)。官方推荐直接实现WebMvcConfigurer或者直接继承WebMvcConfigurationSupport,
1)实现WebMvcConfigurer接口(推荐),
2)继承WebMvcConfigurationSupport类

@Configuration
public class LWebMvcConfigurer implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        ArrayList<String> whiteList = new ArrayList<>();
        whiteList.add("/login");
        whiteList.add("/logout");
        registry.addInterceptor(new AuthInterceptor())
                .excludePathPatterns(whiteList)
                .addPathPatterns("/**");
    }
}

第5步:创建HelloController 来验证从threadlocal中获取数据:

@RestController
public class HelloController {

    @RequestMapping(value = "/hello", method = RequestMethod.GET)
    public String hello() {
        String token = ContextManager.getToken();
        if(!StringUtils.hasLength(token)){
            return "please login!";
        }
        log.info("token:"+ token);
        String userId = ContextManager.getUserId();
        if(!StringUtils.hasLength(userId)){
            return "please login!";
        }
        log.info("userId:"+ userId);
        return  "hello world!";
    }
}

2 测试验证

2.1 请求有token

在这里插入图片描述
controller中获取token:在这里插入图片描述

2.2 请求没有token

在这里插入图片描述
需要用户的请求header中增加token。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值