并发导致的用户信息错乱

15 篇文章 0 订阅

问题 多个用户登录bi系统,假设用户1有报表1的权限,用户2有报表2的权限。但是发现有时用户1此时无法访问报表1,提示信息是无权限。。。看下用户信息的设置和获取的相关代码:
保存用户信息的实体类,使用了TreadLocal保证线程安全:

public class LocalUser {
    private ThreadLocal<User> localCache = new ThreadLocal<User>();
    private ThreadLocal<String> localBiUser = new ThreadLocal<String>();

    private static LocalUser localUser = new LocalUser();

    public static LocalUser getInstance() {
        return localUser;
    }

    public User getUser() {
        return localCache.get();
    }

    public void setUser(User user) {
        localCache.set(user);
    }

    public String getBiUser() {
        return localBiUser.get();
    }

    public void setBiUser(String biUserInfo) {
        localBiUser.set(biUserInfo);
    }
}


用户信息的设置

public class LocalSecurityFilter implements Filter {
 @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

    // 处理

    if ("/bi.html".equals(hsr.getServletPath())) {
        String servletPath = hsr.getServletPath();
        String biUserInfo = getCookieValue("bi_usertoken", (HttpServletRequest)servletRequest);
        LocalUser.getInstance().setBiUser(new String(DESEncryptTools.decrypt(biUserInfo)));
        LOG.info("设置用户信息:"+new String(DESEncryptTools.decrypt(biUserInfo))+  "   线程: " +Thread.currentThread().getName());

    }

    // 处理
    }

}

用户信息的获取:

userid3 = LocalUser.getInstance().getUser().getUserId();
userName3 = LocalUser.getInstance().getUser().getUsername();
log.info("获取用户信息:"+  "   线程: " +Thread.currentThread().getName()+" "+userName3) ;


在设置用户和获取用户的地方分别加日志,然后日志内容如下:
[INFO]-[2019-08-02 14:16:10]-[LocalSecurityFilter.doFilter():96]-[http-nio-8083-exec-7] 设置用户信息:mazhen   线程: http-nio-8083-exec-7
[INFO]-[2019-08-02 14:16:12]-[BoardRoleService.getBoardData():86]-[http-nio-8083-exec-5] 获取用户信息:   线程: http-nio-8083-exec-5 null
[INFO]-[2019-08-02 14:16:13]-[BoardRoleService.getBoardData():86]-[http-nio-8083-exec-7] 获取用户信息:   线程: http-nio-8083-exec-7 马振
[INFO]-[2019-08-02 14:38:33]-[LocalSecurityFilter.doFilter():96]-[http-nio-8083-exec-7] 设置用户信息:mazhen   线程: http-nio-8083-exec-7
[INFO]-[2019-08-02 14:38:34]-[BoardRoleService.getBoardData():86]-[http-nio-8083-exec-4] 获取用户信息:   线程: http-nio-8083-exec-4 null


日志能说明两点:
1 可以看出 线程exec-7 用户信息都是马振,所以一定是使用了线程池,而且线程在重复利用
2 一次页面的面板展示会使用多线程进行多次请求,而不是一个线程处理所有.

一个页面的展示,会有如下请求:


上面用户信息保存的代码:将用户信息保存到threadLocal中,这个的确是线程安全的,但是因为访问一个页面会同时发出多个http请求,而处理多个http请求tomcat会从线程池中获取多个线程来并发处理。
所以上面用户信息的保存仅仅是保存到处理 满足"/bi.html".equals(hsr.getServletPath() 要求的线程中,别的线程并没有当前用户的信息,别的线程的用户信息会为空或者是别的用户的信息。

所以上面保存用户信息的方式完全就是错误的,不是典型的多并发导致的问题,而是对web请求认识不清,以为某个用户会使用同一个线程。


上面的解决方案是,每个请求进来通过过滤器的时候都要设置用户信息,将用户信息设置为当前的请求对应的用户
 

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值