写一个aop,实现用户身份验证和所传入参数判空

用于app端访问方法时的用户身份验证和所传入参数判空,还有登录用户超时限制,限制单个用户在多设备登录。

采用注解,每个用户分配一个token,存于redis中。

1.开启aop功能

 在项目相关xml配置文件加入

<aop:aspectj-autoproxy proxy-target-class="true" />

2.定义注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface ValidUserAndParams {
   //用户token String token()
default "token";
   //用户返回值 String resultCode()
default "code";
//传入参数 String[] params()
default {}; }

3.定义切面

@Component
@Aspect
public class ValidAspect {

    @Autowired
    private ValidUtil validUtil;

    @Around("execution(public Object packagename..*.*(..)) && @annotation(vup)")
    public Object userAndParamsCheck(ProceedingJoinPoint joinPoint,ValidUserAndParams vup) {
        return validkUtil.checkUser(joinPoint,vup);
    }
}

ValidUtil.java

@Component
public class ValidUtil {

    @Autowired
    private UserToken userToken;
    
    public Object checkUser(ProceedingJoinPoint joinPoint,ValidUserAndParams vup) {
        TwoTuple<Boolean,JSONObject> tokenInfo=null;
        try{
            Object[] params=joinPoint.getArgs();
            if(params[0] instanceof HttpServletRequest){
                HttpServletRequest request=(HttpServletRequest)params[0];
                tokenInfo=userToken.isValidToken(request,ac.token(),ac.resultCode());
                if(!tokenInfo.first)
                    return tokenInfo.second;
                for(String i : ac.params()){
                    if(null==request.getParameter(i)||"".equals(request.getParameter(i))){
                        tokenInfo.second.put("code", Code.paramValueInvalid);
                        tokenInfo.second.put("msg","参数 "+i+" 不能为空");
                        return tokenInfo.second;
                    }
                }
            }
            return joinPoint.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        return tokenInfo.second;
    }

}

UserToken.java

@Component
public class UserToken {

    @Autowired
    private RedisExeUtil redisExeUtil;

    @Autowired
    private ConfigInfo configInfo;

    /**
     * 用户校验通过之后需要调用此方法来分配token
     * 1.如果该用户此前已经登录且token没有过期,就删除该未过期的token
     * 2.如果不存在token就生成该token码
     * 3.生成token码之后就将token码保存
     * @param userName
     * @return
     */
    public String distributionToken(String userName){       //用户登录的时候,分配token的
        String token=redisExeUtil.getMpVByK(CreateRedisKey.createUser2TokenKey(),userName);
        if(token!=null)     //删除之前存在的映射关系
            redisExeUtil.deletevalue(CreateRedisKey.createToken2User(token));   //删除之前记录的token
        //重新分配新的token  并记录token的信息
        String newToken=HashFactory.hashKeyForDisk(System.currentTimeMillis()+userName);    //计算该用户名的hash
        redisExeUtil.expire(CreateRedisKey.createToken2User(newToken), 1800, userName);        //hash-->userName   保存了Hash到userName的映射关系
        //记录user->token的信息
        redisExeUtil.addMpKV(CreateRedisKey.createUser2TokenKey(),userName,newToken);
        return newToken;
    }

    /**
     * 1.可能已经过期,如果过期就返回响应的过期提示(可能用户在另外一台设备登录或已超时)
     * 2.没有过期,返回响应的用户名
     * @param token
     * @return
     */
    public JSONObject getUserNameByToken(String token){
        JSONObject result=new JSONObject();
        if(token==null || "".equals(token)){
            result.put("code", Code.tokenIsError);
            result.put("msg","token为空");   //是否清空表中的数据
            return result;
        }

        String userName=redisExeUtil.getStringVal(CreateRedisKey.createToken2User(token));

        if(userName==null){
            result.put("code", Code.tokenIsError);
            result.put("msg","登录超时,或者被其它设备登录");   //是否清空表中的数据
        }else{
            result.put("code", Code.success);
            result.put("msg","token验证通过");
            result.put("name",userName);
       //设置app端用户的登录失效时间为30分钟,单位为秒,-1表示不过期 redisExeUtil.expire(CreateRedisKey.createToken2User(token), 1800, userName); }
return result; //过期了就没有了,重新登录就会分配新的token码 } public JSONObject getUserNameByToken(HttpServletRequest request,String tokenName){ String token=request.getParameter(tokenName); return getUserNameByToken(token); } public boolean isValidToken(JSONObject tokenObj,String code){ return tokenObj.getInteger(code)==Code.success; } public TwoTuple<Boolean,JSONObject> isValidToken(HttpServletRequest request,String tokenName,String code){ JSONObject tokenObj=getUserNameByToken(request,tokenName); return TupleUtil.tuple(isValidToken(tokenObj,code),tokenObj); } }

写了个泛型二元组TwoTuple.java

public class TwoTuple<X,Y> {
    public final X first;

    public final Y second;

    public TwoTuple(X x,Y y){
        this.first=x;
        this.second=y;
    }
}

HashFactory.java

public class HashFactory {

    public static String hashKeyForDisk(String key) {
        String cacheKey;
        try {
            final MessageDigest mDigest = MessageDigest.getInstance("MD5");
            mDigest.update(key.getBytes());
            cacheKey = bytesToHexString(mDigest.digest());
        } catch (NoSuchAlgorithmException e) {
            cacheKey = String.valueOf(key.hashCode());
        }
        return cacheKey;
    }


    private static String bytesToHexString(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            String hex = Integer.toHexString(0xFF & bytes[i]);
            if (hex.length() == 1) {
                sb.append('0');
            }
            sb.append(hex);
        }
        return sb.toString();
    }
}

redis的命令封装类RedisExeUtil.java

@Component
public class RedisExeUtil {


    @Autowired
    private  RedisManager redisManager;

    @Autowired
    private CheckUtil check;

    //---------------------------------------String类型数据------------------------------------------------/**
     * 作用:将传入的k,v写入到redis
     *          redis管理对象
     * @param key : 存入redis的key
     *
     * @param value : 支持的类型为 String Number Object
     *                 如果为Object存储的就为其转化为JSON字符串后的值
     */
    public String writeString(String key,Object value){
        return (String)redisManager.execute(new RedisDaoIf() {
            @Override
            public Object execute(Jedis jedis, Object... params) {
                String key = (String) params[0];
                Object value = params[1];
                if(value instanceof Number || value instanceof String){
                    jedis.set(key, value+"");
                }else{
                    jedis.set(key,JSONObject.fromObject(value).toString());
                }
                return key;
            }
        },key,value);
    }


    /**
     * 作用:根据传入的key获取该key对应的String值
     * @param key
     *          需要获取的key值
     * @return
     */
    public  String getStringVal(String key){
        return (String)redisManager.execute(new RedisDaoIf() {
            @Override
            public Object execute(Jedis jedis, Object... params) {
//                Pipeline pipeline=jedis.pipelined();
                String key = (String) params[0];
                return jedis.get(key);
            }
        },key);
    }


    //---------------------------------------List类型数据------------------------------------------------

    /**
     * 作用:使用增量的方式向redis中追加List值
     *      使用方法见   writeList
     * @param key
     * @param value
     * @return
     */
    public  int writeListIncrement(String key,Collection<? extends Object> value){
        return writeList(key,value,true);
    }

    /**
     * 作用:向redis中写入一个全新的List,也就是使用非增量写
     *      使用方法见   writeList
     * @param key
     * @param value
     * @return
     */
    public  int writeNewList(String key,Collection<? extends Object> value){
        return writeList(key,value,false);
    }


    /**
     * 作用:用于将集合写入到redis中
     * @param key
     * @param value
     * @param Isadd  : 如果此处为真则表明是向集合中追加,否则将删除该key原有的值,然后在生成该key
     *        集合支持的类型有String,Number,如果为其它类型将会存储 ClassName@Hash 信息
     * @return
     *        存入到redis中集合的大小
     */
    public  int writeList(String key,Collection<? extends Object> value,boolean Isadd){

        return (Integer)redisManager.execute(new RedisDaoIf() {
            @Override
            public Object execute(Jedis jedis, Object... params) {
                Pipeline pipeline=jedis.pipelined();
                String key=(String)params[0];
                Object[] tmp=((Collection)params[1]).toArray();
                String [] a=new String[tmp.length];
                for(int i=0;i<tmp.length;i++){
                    a[i]=tmp[i]+"";
                }
                boolean Isadd=(boolean)params[2];
                if(!Isadd){
                    if(jedis.exists(key))
                        pipeline.del(key);
                }
                pipeline.lpush(key,a);
                return a.length;
            }
        },key,value,Isadd);
    }

    /**
     * 作用:通过key获取该key下面的List结构的数据
     *
     *          redis管理对象
     * @param key
     *          key值
     * @return
     */
    public  List<String> getListString(String key){
        return ( List<String>)redisManager.execute(new RedisDaoIf() {
            @Override
            public Object execute(Jedis jedis, Object... params) {
//                Pipeline pipeline=jedis.pipelined();
                String key = (String) params[0];
                return jedis.lrange(key,0,-1);
            }
        },key);
    }

    public  List<String> getListFirstEle(String key){
        return ( List<String>)redisManager.execute(new RedisDaoIf() {
            @Override
            public Object execute(Jedis jedis, Object... params) {
//                Pipeline pipeline=jedis.pipelined();
                String key = (String) params[0];
                return jedis.lrange(key,0,0);
            }
        },key);
    }


    //---------------------------------------Map类型数据  redis中关于Map的操作函数都是以h开头------------------------------------------------

    /**
     * 作用:根据key得到该key对应的Map对象
     * @param key
     * @return
     */
    public  Map<String,String> getMapString(String key){
        return (Map<String,String>)redisManager.execute(new RedisDaoIf() {
            @Override
            public Object execute(Jedis jedis, Object... params) {
//                Pipeline pipeline=jedis.pipelined();
                String key = (String) params[0];
                return jedis.hgetAll(key);
            }
        },key);
    }

    /**
     * 作用:用于将Map类型的数据写到Redis中  返回值为插入到redis中Map的size
     *        Map<ObjectKey,ObjectValue> 其中ObjectKey支持的数据类型有 String Number
     *                  ObjectValue中支持的数据类型有 String Number Collection
     *                  如果ObjectValue中的数据不为上面三种而为Object,将会被转化为JSON对象字符串
     * @param key
     * @param value
     */
    public Integer writeMap(String key,Map<? extends Object,? extends Object> value){
        Integer result=(Integer)redisManager.execute(new RedisDaoIf() {
            @Override
            public Object execute(Jedis jedis, Object... params) {
                Pipeline pipeline=jedis.pipelined();
                Object key = params[0];
                Map<Object, Object> value = (Map<Object, Object>) params[1];
                Map<String, String> tmp = new HashMap<String, String>();
                for (Object o : value.keySet()) {
                    Object vo=value.get(o);
                    if(vo instanceof String || vo instanceof Number){
                        tmp.put(o + "",  vo+ "");
                    }else if(vo instanceof  Collection) {
                        tmp.put(o + "", JSONArray.fromObject(vo).toString());
                    }else{
                        tmp.put(o + "", JSONObject.fromObject(vo).toString());
                    }
                }
                pipeline.hmset(key + "", tmp);
                return value.size();
            }
        }, key, value);
        return result;
    }

    /**
     * 作用:用于获取map结构中的某个值
     * @param redisKey  : redis的key值
     * @param mapKey    :map中的key值
     * @return
     */
    public  String getMpVByK(String redisKey,String mapKey){
        return (String)redisManager.execute(new RedisDaoIf() {
            @Override
            public Object execute(Jedis jedis, Object... params) {
                return jedis.hget((String) params[0], (String) params[1]);
            }
        },redisKey,mapKey);
    }

    /**
     * 作用:用于删除Map结构中的某个KV对
     * @param redisKey
     * @param mapKey
     * @return
     */
    public  String delMpKVByK(String redisKey,String mapKey){
        return (String)redisManager.execute(new RedisDaoIf() {
            @Override
            public Object execute(Jedis jedis, Object... params) {
                Pipeline pipeline=jedis.pipelined();
                pipeline.hdel((String) params[0], (String) params[1]);
                return (String)params[1];
            }
        },redisKey,mapKey);
    }

    /**
     * 作用:向redis中的Map结构中增加一个KV对
     *  Hset 命令用于为哈希表中的字段赋值 。
     *  如果哈希表不存在,一个新的哈希表被创建并进行HSET操作。
     *  如果字段已经存在于哈希表中,旧值将被覆盖。
     * @param redisKey      : redis中的key
     * @param mapKey        : 需要存储的map的key
     * @param value         : 需要存储的map的v
     * @return              :  返回已经插入到map中的key值
     */
    public  String addMpKV(String redisKey,String mapKey,Object value){
        return (String)redisManager.execute(new RedisDaoIf() {
            @Override
            public Object execute(Jedis jedis, Object... params) {
                Pipeline pipeline=jedis.pipelined();
                Object o =params[2];
                if(o instanceof String || o instanceof  Number){
                    pipeline.hset((String)params[0],(String)params[1],o+"");
                }else if(o instanceof Collection){
                    pipeline.hset((String) params[0], (String) params[1], JSONArray.fromObject(o).toString());
                }else{
                    pipeline.hset((String)params[0],(String)params[1],JSONObject.fromObject(o).toString());
                }
                return (String)params[0];
            }
        },redisKey,mapKey,value);
    }

    /**
     * 作用:获取某个Map结构中的全部key值
     * @param key
     * @return
     */
    public  Set<String> getMapKs(String key){
        return (Set<String>)redisManager.execute(new RedisDaoIf() {
            @Override
            public Object execute(Jedis jedis, Object... params) {
                return jedis.hkeys((String)params[0]);
            }
        },key);
    }

    /**
     * 作用:用于获取某个Map结构中的全部value值
     * @param key
     * @return
     */
    public  List<String> getMapVs(String key){
        return (List<String>)redisManager.execute(new RedisDaoIf() {
            @Override
            public Object execute(Jedis jedis, Object... params) {
                return jedis.hvals((String)params[0]);
            }
        },key);
    }






//---------------------------------------删除key值------------------------------------------------

    /**
     * 作用:在redis中删除不需要的key
     *          redis管理对象
     * @param keys :需要删除的key ,可以传入多个Key
     * @return int : 实际删除的key值的数量,注意此数量并不准确,切勿用作对数量要求比较高的判断
     */
    public  int deletevalue(String... keys){
        String[] a= (String[]) keys;
        return deleteKey(a);
    }

    /**
     * 作用:用于批量删除redis中的key
     * @param keys  :此集合为所有需要删除的Key的集合
     * @return
     */
    public int deletevalue(Collection<String> keys){
        if(null == keys))
            return 0;
        String[] strs=new String[keys.size()];
        String[] a=keys.toArray(strs);
        //String[] a= (String[]) keys.toArray();
        return deleteKey(a);
    }


    /**
     * 作用:用于删除redis不需要的Key
     * @param keys      :为需要删除的key的数组
     * @return
     */
    private int deleteKey(String[] keys){
        return (Integer)redisManager.execute(new RedisDaoIf() {
            @Override
            public Object execute(Jedis jedis, Object... params) {
                Pipeline pipeline=jedis.pipelined();
                String[] a= (String[]) params;
                pipeline.del(a);
                return a.length;
            }
        },keys);
    }

    /**
     * 作用:用于判断某个key是否存在
     * @param key   被判断的key值
     * @return
     */
    public  boolean IskeyExist(String key){
        return (boolean)redisManager.execute(new RedisDaoIf() {
            @Override
            public Object execute(Jedis jedis, Object... params) {
                String key=(String)params[0];
                return jedis.exists(key);
            }
        },key);
    }

    /**
     * 作用:用于修改redis中key的值
     * @param oldKey    :存在于redis中的key值
     * @param newKey    :需要修改成的key值
     * @return
     */
    public String renameKey(String oldKey,String newKey){
        return (String)redisManager.execute(new RedisDaoIf() {
            @Override
            public Object execute(Jedis jedis, Object... params) {
                Pipeline pipeline=jedis.pipelined();
                pipeline.rename((String)params[0],(String)params[1]);
                return  params[1];
            }
        },oldKey,newKey);
    }

    /**
     * 设置redis中的key value 同时设置该key的过期时间
     * @param key
     * @param second
     * @param value
     * @return
     */
    public boolean expire(String key,int second,String value){
        return (boolean)redisManager.execute(new RedisDaoIf(){
            @Override
            public Object execute(Jedis jedis, Object... params) {
                jedis.setex((String)params[0],(int)params[1],(String)params[2]);
                return true;
            }
        },key,second,value);
    }


}

 redis的配置类RedisManger.java

public class RedisManager {
    private String hostname;
    private int port;
    private String password;
    private int dbid;
    private String clientName;
    private int timeout;
    private JedisPool pool;

    //可用连接实例的最大数目,默认值为8;
    //如果赋值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted(耗尽)。
    private static int MAX_ACTIVE = 1024;

    //控制一个pool最多有多少个状态为idle(空闲的)的jedis实例,默认值也是8。
    private static int MAX_IDLE = 200;

    //等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。如果超过等待时间,则直接抛出JedisConnectionException;
    private static int MAX_WAIT = 10000;
    //在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的;
    private static boolean TEST_ON_BORROW = true;

    /**
     * 初始化redis的连接池
     * 注意本方法只有在系统启动的时候调用,其它时候禁止调用
     */
    public void init(){
        if(pool==null){
            synchronized (this) {
                if(pool==null){
                    JedisPoolConfig config = new JedisPoolConfig();
                    config.setMaxTotal(MAX_ACTIVE);
                    config.setMaxIdle(MAX_IDLE);
                    config.setMaxWaitMillis(MAX_WAIT);
                    config.setTestOnBorrow(TEST_ON_BORROW);
                    //在将连接放回池中前,自动检验连接是否有效
                    config.setTestOnReturn(true);
                    //自动测试池中的空闲连接是否都是可用连接
                    config.setTestWhileIdle(true);
                    pool = new JedisPool(config,this.hostname, this.port, this.timeout, this.password, this.dbid, this.clientName);
                }
            }
        }
    }


    public JedisPool getJedisPool(){
        return pool;
    }

    public Object execute(RedisDaoIf dao, Object ... params) {
        Jedis jedis = this.pool.getResource();
        boolean hasExcep = false;
        try {
            try {
                return dao.execute(jedis, params);
            } catch (JedisException ex) {
                hasExcep = true;
                throw ex;
            }
        } finally {
            if (hasExcep) {
                this.pool.returnBrokenResource(jedis);
            } else {
                this.pool.returnResource(jedis);
            }
        }
    }

    public String getHostname() {
        return hostname;
    }


    public void setHostname(String hostname) {
        this.hostname = hostname;
    }


    public int getPort() {
        return port;
    }


    public void setPort(int port) {
        this.port = port;
    }


    public String getPassword() {
        return password;
    }


    public void setPassword(String password) {
        this.password = password;
    }


    public int getDbid() {
        return dbid;
    }


    public void setDbid(int dbid) {
        this.dbid = dbid;
    }


    public String getClientName() {
        return clientName;
    }


    public void setClientName(String clientName) {
        this.clientName = clientName;
    }


    public int getTimeout() {
        return timeout;
    }


    public void setTimeout(int timeout) {
        this.timeout = timeout;
    }


    public JedisPool getPool() {
        return pool;
    }


    public void setPool(JedisPool pool) {
        this.pool = pool;
    }
}

具体信息位于xml文件

<bean id="redisManager" class="huayuutil.redis.RedisManager" init-method="init">
        <!-- redis的连接地址 -->
        <property name="hostname" value="127.0.0.1" />
        <!-- redis的端口 -->
        <property name="port" value="6379"/>
        <!-- redis的密码 -->
        <property name="password" value="xxxxxx"/>
        <!-- redis的连接库 -->
        <property name="dbid" value="1"/>
        <!-- 指定redis客户端的名称 -->
        <property name="clientName" value="redis"/>
        <!-- 指定redis的超时时间 -->
        <property name="timeout" value="10000"/>

</bean>

 以上为用户登录过之后的校验。以下为某用户的初次登录分配token。

 

 



posted @ 2018-01-22 08:31  daidao  阅读(661)  评论(0)    收藏  举报