• Springboot+JWT+Redis实现登陆登出功能


    1:什么是Token?:三部分组成:头+有效负载+签名

    1.1 JWT创建中的一些方法讲解:

     public static String createTokenWithClaim(User user){
            //构建头部信息
            Map<String,Object> map = new HashMap<>();
            map.put("typ","JWT");
            map.put("alg","HS256");
            //构建密钥信息。使用自定义token密钥还是用户密码都可以,选择不一样,在解密的时候会不一样。一般建议自定义,安全、方便
            Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);    //使用自定义的token密钥
    //        Algorithm algorithm = Algorithm.HMAC256(user.getRead_userpass());   //使用用户输入的用户密码作为密钥
            //通过自定义声明并组合头部细腻些和密钥信息生成jwt token
     
            Date nowDate = new Date();
            Date expireDate = new Date(System.currentTimeMillis() + EXPIRE_TIME);   //过期时间预处理
     
            String token = JWT.create().withHeader(map)
                    .withClaim("loginName",user.getRead_username()) //自定义,登录用户名
                    .withClaim("deptName","技术部")    //自定义,部门
                    .withClaim("loginPass",user.getRead_userpass()) //自定义,登录用户密码
                    .withIssuer("SERVICE") // 声明,签名是有谁生成 例如 服务器
                    .withSubject("this is test token") //声明, 签名的主题
                    // .withNotBefore(new Date()) //声明,定义在什么时间之前,该jwt都是不可用的
                    .withAudience("APP") //声明, 签名的观众 也可以理解谁接受签名的
                    .withIssuedAt(nowDate) //声明, 生成签名的时间
                    .withExpiresAt(expireDate)//声明, 签名过期的时间
                    .sign(algorithm);   //签名signature
     
           return token;
        }
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    1.2: JWT解密中的一些方法讲解:

      /**
         * 验证jwt token
         * 如果在生成token的步奏中构建密钥信息使用了用户密码,则在解密的时候,同样构建密钥信息的时候需要用户密码
         */
        public static void verifyToken(String token){
            //构建密钥信息
            Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
            //通过密钥信息和签名的发布者的信息生成JWTVerifier(JWT验证类)。不提那家发布者的信息也可以获取JWTVerifier
            JWTVerifier verifier = JWT.require(algorithm)
    //                .withIssuer("SERVICE")  //不添加.withIssuer("SERVICE") 也可以获取JWTVerifier
                    .build();
            //通过JWTVerifier获取token中的信息
            DecodedJWT jwt = verifier.verify(token);
     
            //获取token中的声明和自定义声明
            String subject = jwt.getSubject();
            List<String> audience = jwt.getAudience();
            Map<String, Claim> claims = jwt.getClaims();
            for (Map.Entry<String, Claim> entry : claims.entrySet()){
                String key = entry.getKey();
                Claim claim = entry.getValue();
                String value = claim.asString();
                System.out.println("key:"+key+" value:"+claim.asString());
            }
        }
     
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    2:Springboot+JWT+Redis实现登陆登出功能

    2.1:首先我们在pom引入redis:

       <!--  JWT  -->
            <dependency>
                <groupId>com.auth0</groupId>
                <artifactId>java-jwt</artifactId>
                <version>3.4.0</version>
            </dependency>
    
    
            <!--  Redis依赖   -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-redis</artifactId>
                <!-- 1.5的版本默认采用的连接池技术是jedis  2.0以上版本默认连接池是lettuce, 在这里采用jedis,所以需要排除lettuce的jar -->
                <exclusions>
                    <exclusion>
                        <groupId>redis.clients</groupId>
                        <artifactId>jedis</artifactId>
                    </exclusion>
                    <exclusion>
                        <groupId>io.lettuce</groupId>
                        <artifactId>lettuce-core</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
            <!-- 添加jedis客户端 -->
            <dependency>
                <groupId>redis.clients</groupId>
                <artifactId>jedis</artifactId>
                <version>2.9.0</version>
            </dependency>
            <!--spring2.0集成redis所需common-pool2-->
            <!-- 必须加上,jedis依赖此  -->
            <!-- spring boot 2.0 的操作手册有标注 大家可以去看看 地址是:https://docs.spring.io/spring-boot/docs/2.0.3.RELEASE/reference/htmlsingle/-->
            <dependency>
                <groupId>org.apache.commons</groupId>
                <artifactId>commons-pool2</artifactId>
                <version>RELEASE</version>
            </dependency>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    2.2:在application.yml中配置:

      redis:
        # Redis服务器地址
        host: 127.0.0.1
        # Redis数据库索引(默认为0)
        database: 0
        # Redis服务器连接端口
        port: 6379
        password:
        #连接超时时间(毫秒)
        timeout: 3600
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    2.3:基础的BaseRedisConfig配置类,序列化:

    package com.example.common;
    
    import com.fasterxml.jackson.annotation.JsonAutoDetect;
    import com.fasterxml.jackson.annotation.PropertyAccessor;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import org.springframework.cache.CacheManager;
    import org.springframework.cache.annotation.EnableCaching;
    import org.springframework.cache.interceptor.KeyGenerator;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.redis.cache.RedisCacheConfiguration;
    import org.springframework.data.redis.cache.RedisCacheManager;
    import org.springframework.data.redis.connection.RedisConnectionFactory;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
    import org.springframework.data.redis.serializer.RedisSerializationContext;
    import org.springframework.data.redis.serializer.RedisSerializer;
    import org.springframework.data.redis.serializer.StringRedisSerializer;
    
    import java.lang.reflect.Method;
    import java.time.Duration;
    
    @Configuration
    @EnableCaching
    public class BaseRedisConfig {
    
        /**
         * 自定义key规则
         * @return
         */
        @Bean
        public KeyGenerator keyGenerator() {
            return new KeyGenerator() {
                @Override
                public Object generate(Object target, Method method, Object... params) {
                    StringBuilder sb = new StringBuilder();
                    sb.append(target.getClass().getName());
                    sb.append(method.getName());
                    for (Object obj : params) {
                        sb.append(obj.toString());
                    }
                    return sb.toString();
                }
            };
        }
    
        /**
         * 设置RedisTemplate规则
         * @param redisConnectionFactory
         * @return
         */
        @Bean
        public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
            RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
            redisTemplate.setConnectionFactory(redisConnectionFactory);
            Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
    
            //解决查询缓存转换异常的问题
            ObjectMapper om = new ObjectMapper();
            // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
            om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
            // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
            om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
            jackson2JsonRedisSerializer.setObjectMapper(om);
    
            //序列号key value
            redisTemplate.setKeySerializer(new StringRedisSerializer());
            redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
            redisTemplate.setHashKeySerializer(new StringRedisSerializer());
            redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
    
            redisTemplate.afterPropertiesSet();
            return redisTemplate;
        }
    
        /**
         * 设置CacheManager缓存规则
         * @param factory
         * @return
         */
        @Bean
        public CacheManager cacheManager(RedisConnectionFactory factory) {
            RedisSerializer<String> redisSerializer = new StringRedisSerializer();
            Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
    
            //解决查询缓存转换异常的问题
            ObjectMapper om = new ObjectMapper();
            om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
            om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
            jackson2JsonRedisSerializer.setObjectMapper(om);
    
            // 配置序列化(解决乱码的问题),过期时间600秒
            RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                    .entryTtl(Duration.ofSeconds(600))
                    .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
                    .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
                    .disableCachingNullValues();
    
            RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
                    .cacheDefaults(config)
                    .build();
            return cacheManager;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105

    2.4:对redis中的redisTemplate封装:(接口和实现类)

    请添加图片描述

    package com.example.service;
    import org.springframework.data.domain.Sort;
    import org.springframework.data.geo.Distance;
    import org.springframework.data.geo.GeoResults;
    import org.springframework.data.geo.Point;
    import org.springframework.data.redis.connection.RedisGeoCommands;
    
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    
    /**
     * ClassName: RedisService 
    * Description: redis操作接口
    */
    public interface RedisService { /** * 保存属性 * * @param key key值 * @param value value值 * @param time 时间戳 */ void set(String key, Object value, long time); /** * 保存属性 * * @param key key值 * @param value value值 */ void set(String key, Object value); /** * 获取属性 * * @param key key值 * @return 返回对象 */ Object get(String key); /** * 删除属性 * * @param key key值 * @return 返回成功 */ Boolean del(String key); /** * 批量删除属性 * * @param keys key值集合 * @return 返回删除数量 */ Long del(List<String> keys); /** * 设置过期时间 * * @param key key值 * @param time 时间戳 * @return 返回成功 */ Boolean expire(String key, long time); /** * 获取过期时间 * * @param key key值 * @return 返回时间戳 */ Long getExpire(String key); /** * 判断key是否存在 * * @param key key值 * @return 返回 */ Boolean hasKey(String key); /** * 按delta递增 * * @param key key值 * @param delta delta值 * @return 返回递增后结果 */ Long incr(String key, long delta); /** * 按delta递减 * * @param key key值 * @param delta delta值 * @return 返回递减后结果 */ Long decr(String key, long delta); /** * 获取Hash结构中的属性 * * @param key 外部key值 * @param hashKey 内部key值 * @return 返回内部key的value */ Object hGet(String key, String hashKey); /** * 向Hash结构中放入一个属性 * * @param key 外部key * @param hashKey 内部key * @param value 内部key的value * @param time 过期时间 * @return 返回是否成功 */ Boolean hSet(String key, String hashKey, Object value, long time); /** * 向Hash结构中放入一个属性 * * @param key 外部key * @param hashKey 内部key * @param value 内部key的value */ void hSet(String key, String hashKey, Object value); /** * 直接获取整个Hash结构 * * @param key 外部key值 * @return 返回hashMap */ Map<Object, Object> hGetAll(String key); /** * 直接设置整个Hash结构 * * @param key 外部key * @param map hashMap值 * @param time 过期时间 * @return 返回是否成功 */ Boolean hSetAll(String key, Map<String, Object> map, long time); /** * 直接设置整个Hash结构 * * @param key 外部key * @param map hashMap值 */ void hSetAll(String key, Map<String, ?> map); /** * 删除Hash结构中的属性 * * @param key 外部key值 * @param hashKey 内部key值 */ void hDel(String key, Object... hashKey); /** * 判断Hash结构中是否有该属性 * * @param key 外部key * @param hashKey 内部key * @return 返回是否存在 */ Boolean hHasKey(String key, String hashKey); /** * Hash结构中属性递增 * * @param key 外部key * @param hashKey 内部key * @param delta 递增条件 * @return 返回递增后的数据 */ Long hIncr(String key, String hashKey, Long delta); /** * Hash结构中属性递减 * * @param key 外部key * @param hashKey 内部key * @param delta 递增条件 * @return 返回递减后的数据 */ Long hDecr(String key, String hashKey, Long delta); /** * 获取Set结构 * * @param key key * @return 返回set集合 */ Set<Object> sMembers(String key); /** * 向Set结构中添加属性 * * @param key key * @param values value集 * @return 返回增加数量 */ Long sAdd(String key, Object... values); /** * 向Set结构中添加属性 * * @param key key * @param time 过期时间 * @param values 值集合 * @return 返回添加的数量 */ Long sAdd(String key, long time, Object... values); /** * 是否为Set中的属性 * * @param key key * @param value value * @return 返回是否存在 */ Boolean sIsMember(String key, Object value); /** * 获取Set结构的长度 * * @param key key * @return 返回长度 */ Long sSize(String key); /** * 删除Set结构中的属性 * * @param key key * @param values value集合 * @return 删除掉的数据量 */ Long sRemove(String key, Object... values); /** * 获取List结构中的属性 * * @param key key * @param start 开始 * @param end 结束 * @return 返回查询的集合 */ List<Object> lRange(String key, long start, long end); /** * 获取List结构的长度 * * @param key key * @return 长度 */ Long lSize(String key); /** * 根据索引获取List中的属性 * * @param key key * @param index 索引 * @return 对象 */ Object lIndex(String key, long index); /** * 向List结构中添加属性 * * @param key key * @param value value * @return 增加后的长度 */ Long lPush(String key, Object value); /** * 向List结构中添加属性 * * @param key key * @param value value * @param time 过期时间 * @return 增加后的长度 */ Long lPush(String key, Object value, long time); /** * 向List结构中批量添加属性 * * @param key key * @param values value 集合 * @return 增加后的长度 */ Long lPushAll(String key, Object... values); /** * 向List结构中批量添加属性 * * @param key key * @param time 过期时间 * @param values value集合 * @return 增加后的长度 */ Long lPushAll(String key, Long time, Object... values); /** * 从List结构中移除属性 * * @param key key * @param count 总量 * @param value value * @return 返回删除后的长度 */ Long lRemove(String key, long count, Object value); /** * 向bitmap中新增值 * * @param key key * @param offset 偏移量 * @param b 状态 * @return 结果 */ Boolean bitAdd(String key, int offset, boolean b); /** * 从bitmap中获取偏移量的值 * * @param key key * @param offset 偏移量 * @return 结果 */ Boolean bitGet(String key, int offset); /** * 获取bitmap的key值总和 * * @param key key * @return 总和 */ Long bitCount(String key); /** * 获取bitmap范围值 * * @param key key * @param limit 范围 * @param offset 开始偏移量 * @return long类型集合 */ List<Long> bitField(String key, int limit, int offset); /** * 获取所有bitmap * * @param key key * @return 以二进制字节数组返回 */ byte[] bitGetAll(String key); /** * 增加坐标 * * @param key key * @param x x * @param y y * @param name 地点名称 * @return 返回结果 */ Long geoAdd(String key, Double x, Double y, String name); /** * 根据城市名称获取坐标集合 * * @param key key * @param place 地点 * @return 坐标集合 */ List<Point> geoGetPointList(String key, Object... place); /** * 计算两个城市之间的距离 * * @param key key * @param placeOne 地点1 * @param placeTow 地点2 * @return 返回距离 */ Distance geoCalculationDistance(String key, String placeOne, String placeTow); /** * 获取附该地点附近的其他地点 * * @param key key * @param place 地点 * @param distance 附近的范围 * @param limit 查几条 * @param sort 排序规则 * @return 返回附近的地点集合 */ GeoResults<RedisGeoCommands.GeoLocation<Object>> geoNearByPlace(String key, String place, Distance distance, long limit, Sort.Direction sort); /** * 获取地点的hash * * @param key key * @param place 地点 * @return 返回集合 */ List<String> geoGetHash(String key, String... place); }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
    • 355
    • 356
    • 357
    • 358
    • 359
    • 360
    • 361
    • 362
    • 363
    • 364
    • 365
    • 366
    • 367
    • 368
    • 369
    • 370
    • 371
    • 372
    • 373
    • 374
    • 375
    • 376
    • 377
    • 378
    • 379
    • 380
    • 381
    • 382
    • 383
    • 384
    • 385
    • 386
    • 387
    • 388
    • 389
    • 390
    • 391
    • 392
    • 393
    • 394
    • 395
    • 396
    • 397
    • 398
    • 399
    • 400
    • 401
    • 402
    • 403
    • 404
    • 405
    • 406
    • 407
    • 408
    • 409
    • 410
    • 411
    • 412
    • 413
    • 414
    • 415
    • 416
    • 417
    • 418

    2.5:RedisServiceImpl

    package com.example.service.impl;
    import com.example.service.RedisService;
    import org.springframework.data.domain.Sort;
    import org.springframework.data.geo.Distance;
    import org.springframework.data.geo.GeoResults;
    import org.springframework.data.geo.Point;
    import org.springframework.data.redis.connection.BitFieldSubCommands;
    import org.springframework.data.redis.connection.RedisGeoCommands;
    import org.springframework.data.redis.core.RedisCallback;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    import java.util.concurrent.TimeUnit;
    
    /**
     * ClassName: RedisServiceImpl 
    * Description: redis操作的具体时间类
    */
    @Service public class RedisServiceImpl implements RedisService { @Resource private RedisTemplate<String, Object> redisTemplate; @Override public void set(String key, Object value, long time) { redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS); } @Override public void set(String key, Object value) { redisTemplate.opsForValue().set(key, value); } @Override public Object get(String key) { return redisTemplate.opsForValue().get(key); } @Override public Boolean del(String key) { return redisTemplate.delete(key); } @Override public Long del(List<String> keys) { return redisTemplate.delete(keys); } @Override public Boolean expire(String key, long time) { return redisTemplate.expire(key, time, TimeUnit.SECONDS); } @Override public Long getExpire(String key) { return redisTemplate.getExpire(key, TimeUnit.SECONDS); } @Override public Boolean hasKey(String key) { return redisTemplate.hasKey(key); } @Override public Long incr(String key, long delta) { return redisTemplate.opsForValue().increment(key, delta); } @Override public Long decr(String key, long delta) { return redisTemplate.opsForValue().increment(key, -delta); } @Override public Object hGet(String key, String hashKey) { return redisTemplate.opsForHash().get(key, hashKey); } @Override public Boolean hSet(String key, String hashKey, Object value, long time) { redisTemplate.opsForHash().put(key, hashKey, value); return expire(key, time); } @Override public void hSet(String key, String hashKey, Object value) { redisTemplate.opsForHash().put(key, hashKey, value); } @Override public Map<Object, Object> hGetAll(String key) { return redisTemplate.opsForHash().entries(key); } @Override public Boolean hSetAll(String key, Map<String, Object> map, long time) { redisTemplate.opsForHash().putAll(key, map); return expire(key, time); } @Override public void hSetAll(String key, Map<String, ?> map) { redisTemplate.opsForHash().putAll(key, map); } @Override public void hDel(String key, Object... hashKey) { redisTemplate.opsForHash().delete(key, hashKey); } @Override public Boolean hHasKey(String key, String hashKey) { return redisTemplate.opsForHash().hasKey(key, hashKey); } @Override public Long hIncr(String key, String hashKey, Long delta) { return redisTemplate.opsForHash().increment(key, hashKey, delta); } @Override public Long hDecr(String key, String hashKey, Long delta) { return redisTemplate.opsForHash().increment(key, hashKey, -delta); } @Override public Set<Object> sMembers(String key) { return redisTemplate.opsForSet().members(key); } @Override public Long sAdd(String key, Object... values) { return redisTemplate.opsForSet().add(key, values); } @Override public Long sAdd(String key, long time, Object... values) { Long count = redisTemplate.opsForSet().add(key, values); expire(key, time); return count; } @Override public Boolean sIsMember(String key, Object value) { return redisTemplate.opsForSet().isMember(key, value); } @Override public Long sSize(String key) { return redisTemplate.opsForSet().size(key); } @Override public Long sRemove(String key, Object... values) { return redisTemplate.opsForSet().remove(key, values); } @Override public List<Object> lRange(String key, long start, long end) { return redisTemplate.opsForList().range(key, start, end); } @Override public Long lSize(String key) { return redisTemplate.opsForList().size(key); } @Override public Object lIndex(String key, long index) { return redisTemplate.opsForList().index(key, index); } @Override public Long lPush(String key, Object value) { return redisTemplate.opsForList().rightPush(key, value); } @Override public Long lPush(String key, Object value, long time) { Long index = redisTemplate.opsForList().rightPush(key, value); expire(key, time); return index; } @Override public Long lPushAll(String key, Object... values) { return redisTemplate.opsForList().rightPushAll(key, values); } @Override public Long lPushAll(String key, Long time, Object... values) { Long count = redisTemplate.opsForList().rightPushAll(key, values); expire(key, time); return count; } @Override public Long lRemove(String key, long count, Object value) { return redisTemplate.opsForList().remove(key, count, value); } @Override public Boolean bitAdd(String key, int offset, boolean b) { return redisTemplate.opsForValue().setBit(key, offset, b); } @Override public Boolean bitGet(String key, int offset) { return redisTemplate.opsForValue().getBit(key, offset); } @Override public Long bitCount(String key) { return redisTemplate.execute((RedisCallback<Long>) con -> con.bitCount(key.getBytes())); } @Override public List<Long> bitField(String key, int limit, int offset) { return redisTemplate.execute((RedisCallback<List<Long>>) con -> con.bitField(key.getBytes(), BitFieldSubCommands.create().get(BitFieldSubCommands.BitFieldType.unsigned(limit)).valueAt(offset))); } @Override public byte[] bitGetAll(String key) { return redisTemplate.execute((RedisCallback<byte[]>) con -> con.get(key.getBytes())); } @Override public Long geoAdd(String key, Double x, Double y, String name) { return redisTemplate.opsForGeo().add(key, new Point(x, y), name); } @Override public List<Point> geoGetPointList(String key, Object... place) { return redisTemplate.opsForGeo().position(key, place); } @Override public Distance geoCalculationDistance(String key, String placeOne, String placeTow) { return redisTemplate.opsForGeo() .distance(key, placeOne, placeTow, RedisGeoCommands.DistanceUnit.KILOMETERS); } @Override public GeoResults<RedisGeoCommands.GeoLocation<Object>> geoNearByPlace(String key, String place, Distance distance, long limit, Sort.Direction sort) { RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().includeCoordinates(); // 判断排序方式 if (Sort.Direction.ASC == sort) { args.sortAscending(); } else { args.sortDescending(); } args.limit(limit); return redisTemplate.opsForGeo() .radius(key, place, distance, args); } @Override public List<String> geoGetHash(String key, String... place) { return redisTemplate.opsForGeo() .hash(key, place); } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270

    2.6:登录接口填写:

      /**
         * 登录
         *
         * @param user
         * @return
         */
        @PostMapping("/login")
        public Result<User> login(@RequestBody User user) {
            User res = userService.login(user);
            //判断该用户是否已经登陆:
            if (redisService.get(user.getUsername())==null){
                // 生成token
                String token = JWT.create()
                                .withAudience(res.getUsername())
                                .sign(Algorithm.HMAC256(res.getPassword()));
                res.setToken(token);
    
                logService.log(user.getUsername(), StrUtil.format("用户 {} 登录系统", user.getUsername()));
                //将token存入redis缓存中:
                redisService.set(res.getUsername(),token,1800);
                return Result.success(res);
            }
            else {
                return  Result.error("500","你已在其他设备登陆");
            }
    
        }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    2.7:登出接口填写:

     /**
         * 退出登录
         */
        @DeleteMapping
        public  Result<?> loginOut(HttpServletRequest request){
            String token = request.getHeader("token");
            String username = JWT.decode(token).getAudience().get(0);
            redisService.del(username);
            return Result.success("退出成功");
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    2.8:拦截器:

    请添加图片描述

    package com.example.common;
    
    import cn.hutool.core.util.StrUtil;
    import com.auth0.jwt.JWT;
    import com.auth0.jwt.JWTVerifier;
    import com.auth0.jwt.algorithms.Algorithm;
    import com.auth0.jwt.exceptions.JWTDecodeException;
    import com.auth0.jwt.exceptions.JWTVerificationException;
    import com.baomidou.mybatisplus.core.toolkit.Wrappers;
    import com.example.entity.User;
    import com.example.exception.CustomException;
    import com.example.service.RedisService;
    import com.example.service.UserService;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.HandlerInterceptor;
    
    import javax.annotation.Resource;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    /**
     * 拦截器
     */
    public class AuthInterceptor implements HandlerInterceptor {
    
        @Resource
        private UserService userService;
    
        @Resource
        private RedisService redisService;
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
    
            String token = request.getHeader("token");
            if (StrUtil.isBlank(token)) {
                throw new CustomException("401", "未获取到token, 请重新登录");
            }
            String username;
            try {
                username = JWT.decode(token).getAudience().get(0);
            } catch (JWTDecodeException j) {
                throw new CustomException("401", "权限验证失败, 请重新登录");
            }
    
            if (redisService.get(username)==null){
                throw new CustomException("401", "token已过期");
            }
    
            // 拿到的token跟redis里面的做比对,看有没有过期
            if (redisService.get(username).equals(token)){
    
                User user = userService.getOne(Wrappers.<User>lambdaQuery().eq(User::getUsername, username));
                if (user == null) {
                    throw new CustomException("401", "用户不存在, 请重新登录");
                }
    
                // 验证 token
                JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build();
                try {
                    jwtVerifier.verify(token);
                } catch (JWTVerificationException e) {
                    throw new CustomException("401", "token不合法, 请重新登录");
                }
    
                return true;
    
            }
    
    
            throw new CustomException("401", "token不一致");
    
    
    
    
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
  • 相关阅读:
    Centos如何安装Mysql
    蓝桥每日一题(day 4: 蓝桥592.门牌制作)--模拟--easy
    FFmpeg和rtsp服务器搭建视频直播流服务
    解决maven依赖冲突,这篇就够了!
    C++标准模板(STL)- 类型支持(基本类型、RTTI、类型特性)
    rmq nameserver
    LambdaQueryWrapper使用 group分组、sum聚合函数 进行统计,并分页排序
    攻防世界-filemanager
    优维低代码:Redirect 路由重定向&If 条件渲染
    A. Morning Sandwich
  • 原文地址:https://blog.csdn.net/justleavel/article/details/127553204