6
回答
java web 开发中关于账户登录后被冻结的问题
利用AWS快速构建适用于生产的无服务器应用程序,免费试用12个月>>>   

如果一个用户在登录成功后被管理员冻结了,后来和这个用户相关的操作失效,user是有一个状态属性的,登录后服务器上的session状态属性是正常的,但被冻结后,这个session的状态属性还是未改变,只是数据库里的数据改变了,如果用在拦截器里判断的换,是不是每次操作都要去查询数据库做判断,这样不高效啊 有没有更好的解决方案啊

举报
Simeone
发帖于4年前 6回/666阅
共有6个答案 最后回答: 4年前

引用来自“_________0”的评论

管理员修改的时候在内存中放一个标识,用户操作的时候都去检测一下,就不用去数据库查询了

引用来自“弗洛韦德”的评论

你是说全局变量吗?还是怎么弄
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.kamike.auth;

import com.kamike.misc.MailUtils;
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 进行安全审计,防止某个IP穷举某个用户的密码
 *
 * @author THiNk
 */
public class SecureInst {

    private SecureInst() {
    }
    private static final SecureInst inst = new SecureInst();

    private static int THRESHOLD = 100;

    private final ConcurrentHashMap<String, Audit> audits = new ConcurrentHashMap<>();
    private final ReentrantLock lock = new ReentrantLock();

    public static SecureInst getInstance() {
        return inst;
    }

    public void alarm(String address,String user)
    {
        MailUtils.sendSystemMail("xinhuavideo@126.com","黑客以["+address+"]地址和用户名["+user+"]发起一次攻击.");
    }
    
    //审计
    public boolean valid(String id, String address) {
        //先清除过期的审计,此处需要测试
        this.clean();
        String key = Audit.key(id, address);

        if (audits.containsKey(key)) {
            Audit audit = audits.get(key);
            if (!audit.old()) {
                if (audit.getFail() > THRESHOLD) {
                    return false;
                } else {
                    return true;
                }
            } else {
                //超过2个小时。就重置,继续允许用户登录
                audit.setFail(0);
                return true;
            }

        }

        return true;

    }

    //清除过期的审计,2个小时后用户可以登陆
    public void clean() {

        Iterator it = audits.values().iterator();

        while (it.hasNext()) {

            Audit audit = (Audit) it.next();

            if (audit.old()) {
                //多线程情况需要测试
                it.remove();
            }
        }

    }

    //审计
    public void fail(String id, String address) {
        String key = Audit.key(id, address);
        if (audits.containsKey(key)) {
            Audit audit = audits.get(key);
            audit.fail();

        } else {
            //第一次用户登录出错的时候,系统会比较慢,线程锁定
            lock.lock();
            try {
                //再次确认
                if (!audits.containsKey(key)) {
                    Audit audit = new Audit();
                    audit.setAddress(address);
                    audit.setId(id);
                    audit.setKey(audit.key());
                    audits.put(audit.getKey(), audit);
                }

            } finally {
                lock.unlock();
            }

        }

    }

    //登陆成功,清除审计
    public void success(String id, String address) {
        try {
            String key = Audit.key(id, address);
            if (audits.containsKey(key)) {
                audits.remove(key);

            } else {

            }
        } catch (Exception ex) {
            //吞掉重复删除的删除的错误,因此在此处加入同步代码,性能销毁太大
        }

    }

}

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.kamike.auth;

import java.util.Date;

/**
 *
 * @author THiNk
 */
public class Audit {

    protected String id;
    protected Date createDate;
    protected Date updateDate;
    protected int fail;
    protected String address;
    protected String key;

    public Audit() {
        this.fail = 0;
        this.createDate = new Date(System.currentTimeMillis());
        this.updateDate = new Date(System.currentTimeMillis());

    }

    public boolean old() {
        Date oldDate = new Date(System.currentTimeMillis() - 3600 * 1000 * 2);
        return oldDate.after(this.updateDate);
    }

    public void fail() {
        this.fail++;
        this.updateDate = new Date(System.currentTimeMillis());
    }

    public String key() {
        return key(id, address);
    }

    public static String key(String id, String address) {
        StringBuilder buffer = new StringBuilder();
        buffer.append(id);
        buffer.append("_");
        buffer.append(address);

        return buffer.toString();
    }

    /**
     * @return the id
     */
    public String getId() {
        return id;
    }

    /**
     * @param id the id to set
     */
    public void setId(String id) {
        this.id = id;
    }

    /**
     * @return the createDate
     */
    public Date getCreateDate() {
        return createDate;
    }

    /**
     * @param createDate the createDate to set
     */
    public void setCreateDate(Date createDate) {
        this.createDate = createDate;
    }

    /**
     * @return the updateDate
     */
    public Date getUpdateDate() {
        return updateDate;
    }

    /**
     * @param updateDate the updateDate to set
     */
    public void setUpdateDate(Date updateDate) {
        this.updateDate = updateDate;
    }

    /**
     * @return the fail
     */
    public int getFail() {
        return fail;
    }

    /**
     * @param fail the fail to set
     */
    public void setFail(int fail) {
        this.fail = fail;
    }

    /**
     * @return the address
     */
    public String getAddress() {
        return address;
    }

    /**
     * @param address the address to set
     */
    public void setAddress(String address) {
        this.address = address;
    }

    /**
     * @return the key
     */
    public String getKey() {
        return key;
    }

    /**
     * @param key the key to set
     */
    public void setKey(String key) {
        this.key = key;
    }

}




管理员修改的时候在内存中放一个标识,用户操作的时候都去检测一下,就不用去数据库查询了

引用来自“_________0”的评论

管理员修改的时候在内存中放一个标识,用户操作的时候都去检测一下,就不用去数据库查询了

你是说全局变量吗?还是怎么弄

引用来自“_________0”的评论

管理员修改的时候在内存中放一个标识,用户操作的时候都去检测一下,就不用去数据库查询了

引用来自“弗洛韦德”的评论

你是说全局变量吗?还是怎么弄

引用来自“Brin想写程序”的评论

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.kamike.auth;

import com.kamike.misc.MailUtils;
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 进行安全审计,防止某个IP穷举某个用户的密码
 *
 * @author THiNk
 */
public class SecureInst {

    private SecureInst() {
    }
    private static final SecureInst inst = new SecureInst();

    private static int THRESHOLD = 100;

    private final ConcurrentHashMap<String, Audit> audits = new ConcurrentHashMap<>();
    private final ReentrantLock lock = new ReentrantLock();

    public static SecureInst getInstance() {
        return inst;
    }

    public void alarm(String address,String user)
    {
        MailUtils.sendSystemMail("xinhuavideo@126.com","黑客以["+address+"]地址和用户名["+user+"]发起一次攻击.");
    }
    
    //审计
    public boolean valid(String id, String address) {
        //先清除过期的审计,此处需要测试
        this.clean();
        String key = Audit.key(id, address);

        if (audits.containsKey(key)) {
            Audit audit = audits.get(key);
            if (!audit.old()) {
                if (audit.getFail() > THRESHOLD) {
                    return false;
                } else {
                    return true;
                }
            } else {
                //超过2个小时。就重置,继续允许用户登录
                audit.setFail(0);
                return true;
            }

        }

        return true;

    }

    //清除过期的审计,2个小时后用户可以登陆
    public void clean() {

        Iterator it = audits.values().iterator();

        while (it.hasNext()) {

            Audit audit = (Audit) it.next();

            if (audit.old()) {
                //多线程情况需要测试
                it.remove();
            }
        }

    }

    //审计
    public void fail(String id, String address) {
        String key = Audit.key(id, address);
        if (audits.containsKey(key)) {
            Audit audit = audits.get(key);
            audit.fail();

        } else {
            //第一次用户登录出错的时候,系统会比较慢,线程锁定
            lock.lock();
            try {
                //再次确认
                if (!audits.containsKey(key)) {
                    Audit audit = new Audit();
                    audit.setAddress(address);
                    audit.setId(id);
                    audit.setKey(audit.key());
                    audits.put(audit.getKey(), audit);
                }

            } finally {
                lock.unlock();
            }

        }

    }

    //登陆成功,清除审计
    public void success(String id, String address) {
        try {
            String key = Audit.key(id, address);
            if (audits.containsKey(key)) {
                audits.remove(key);

            } else {

            }
        } catch (Exception ex) {
            //吞掉重复删除的删除的错误,因此在此处加入同步代码,性能销毁太大
        }

    }

}



好复杂的样子和

引用来自“_________0”的评论

管理员修改的时候在内存中放一个标识,用户操作的时候都去检测一下,就不用去数据库查询了

引用来自“弗洛韦德”的评论

你是说全局变量吗?还是怎么弄

引用来自“Brin想写程序”的评论

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.kamike.auth;

import com.kamike.misc.MailUtils;
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 进行安全审计,防止某个IP穷举某个用户的密码
 *
 * @author THiNk
 */
public class SecureInst {

    private SecureInst() {
    }
    private static final SecureInst inst = new SecureInst();

    private static int THRESHOLD = 100;

    private final ConcurrentHashMap<String, Audit> audits = new ConcurrentHashMap<>();
    private final ReentrantLock lock = new ReentrantLock();

    public static SecureInst getInstance() {
        return inst;
    }

    public void alarm(String address,String user)
    {
        MailUtils.sendSystemMail("xinhuavideo@126.com","黑客以["+address+"]地址和用户名["+user+"]发起一次攻击.");
    }
    
    //审计
    public boolean valid(String id, String address) {
        //先清除过期的审计,此处需要测试
        this.clean();
        String key = Audit.key(id, address);

        if (audits.containsKey(key)) {
            Audit audit = audits.get(key);
            if (!audit.old()) {
                if (audit.getFail() > THRESHOLD) {
                    return false;
                } else {
                    return true;
                }
            } else {
                //超过2个小时。就重置,继续允许用户登录
                audit.setFail(0);
                return true;
            }

        }

        return true;

    }

    //清除过期的审计,2个小时后用户可以登陆
    public void clean() {

        Iterator it = audits.values().iterator();

        while (it.hasNext()) {

            Audit audit = (Audit) it.next();

            if (audit.old()) {
                //多线程情况需要测试
                it.remove();
            }
        }

    }

    //审计
    public void fail(String id, String address) {
        String key = Audit.key(id, address);
        if (audits.containsKey(key)) {
            Audit audit = audits.get(key);
            audit.fail();

        } else {
            //第一次用户登录出错的时候,系统会比较慢,线程锁定
            lock.lock();
            try {
                //再次确认
                if (!audits.containsKey(key)) {
                    Audit audit = new Audit();
                    audit.setAddress(address);
                    audit.setId(id);
                    audit.setKey(audit.key());
                    audits.put(audit.getKey(), audit);
                }

            } finally {
                lock.unlock();
            }

        }

    }

    //登陆成功,清除审计
    public void success(String id, String address) {
        try {
            String key = Audit.key(id, address);
            if (audits.containsKey(key)) {
                audits.remove(key);

            } else {

            }
        } catch (Exception ex) {
            //吞掉重复删除的删除的错误,因此在此处加入同步代码,性能销毁太大
        }

    }

}



引用来自“弗洛韦德”的评论

好复杂的样子和

我这个是防止用户穷举密码的。输入密码出错在2小时内超过100次,就禁止用户再次尝试。

原理是一样,可以参考。用的单例模式和concurrentHashmap


放个全局的HashMap不就行了,用户账号做key,冻结时,将这个用户的账号放到HashMap中,拦截器检查HashMap有没有此用户账号就可以了。



顶部