cookie与session的区别

cookie:客户端技术,存到浏览器中,默认有效时间是回话级别,每次请求自动带cookie值

​            setPath("/")设置什么路径带cookie值,setDomain(".com")设置访问域名带cookie

session:服务端技术,存到服务器中,使用范围是一次回话,session的实现要依赖cookie,

​            像session中放数据时,会返回一个session id,会用cookie进行存储,取值时会先从

​            cookie中取得session id,正常情况下关闭浏览器session不会马上销毁,但是cookie

​            会销毁所以取不到值。若cookie禁用以后还想访问,需要手动将session id拼接处理

​            /网址;jsessionid=id的值

常见单点登录方式

 第一种:session广播,一个模块登陆后,将自己的session复制到其他模块中,可以通过nginx配置

第二种:采用redis+cookie实现,登陆之后将信息放到redis中,key存放唯一的值,value存放用户

信息,在将key放入cookie里,在发送请求时,通过key到redis里查询

第三种:token实现,使用自包含令牌(按规则生成字符串,字符串包含用户信息),客户端保存,服务器不保存回话数据,再访问时拿着上次地址栏返回自包含令牌发送

JWT工具

 jwt生成自包含令牌,有三部分组成:公共部分、私有部分(用户信息)、签名部分(秘钥)

jwt最重要的作用就是对token信息防伪作用

使用token做单点登录,添加依赖

<dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
   </dependency>

工具类

package com.lzq.yygh.common.utils;

import io.jsonwebtoken.*;
import org.springframework.util.StringUtils;

import java.util.Date;

public class JwtHelper {
    //过期时间  毫秒
    private static long tokenExpiration = 24*60*60*1000;
    //自定义秘钥
    private static String tokenSignKey = "123456";
    public static String createToken(Long userId, String userName) {
        String token = Jwts.builder()
                //设置分组
                .setSubject("YYGH-USER")
                //设置字符串过期时间
                .setExpiration(new Date(System.currentTimeMillis() + tokenExpiration))
                        //私有部分
                        .claim("userId", userId)
                        .claim("userName", userName)
                        //设置秘钥
                        .signWith(SignatureAlgorithm.HS512, tokenSignKey)
                        .compressWith(CompressionCodecs.GZIP)
                        .compact();
        return token;
    }
    //从生成token字符串获取userId值
    public static Long getUserId(String token) {
        if(StringUtils.isEmpty(token)) return null;
        Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
        Claims claims = claimsJws.getBody();
        Integer userId = (Integer)claims.get("userId");
        return userId.longValue();
    }
    public static String getUserName(String token) {
        if(StringUtils.isEmpty(token)) return "";
        Jws<Claims> claimsJws
                = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
        Claims claims = claimsJws.getBody();
        return (String)claims.get("userName");
    }

    public static void main(String[] args) {
        String token = JwtHelper.createToken(1L, "55");
        System.out.println(token);
        System.out.println(JwtHelper.getUserId(token));
        System.out.println(JwtHelper.getUserName(token));
    }
}

登录模块调用方法,传入id,name值即可。

使用redis做单点登录

引入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>

配置文件

#配置redis服务
spring.redis.host=127.0.0.1
spring.redis.port=6379
#配置使用redis那个数据库
spring.redis.database=1
#配置redis连接池
spring.redis.jedis.pool.max-active=20
#最大空闲数
spring.redis.jedis.pool.max-idle=10
spring.redis.jedis.pool.min-idle=2

创建配置类,采用重载方式

@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        //key value序列化方式
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        //对hash序列化
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        //注入连接工厂
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        return redisTemplate;

    }
}

serviceImpl中


@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Override
    public RespBean doLogin(LoginVo loginVo , HttpServletRequest request, HttpServletResponse response) {
        String mobile = loginVo.getMobile();
        String password = loginVo.getPassword();
        if (StringUtils.isEmpty(mobile)||StringUtils.isEmpty(password)){
            return RespBean.error(RespBeanEnum.LOGINVO_ERROR);
        }
        if (!ValidatorUtil.isMobile(mobile)){
            return RespBean.error(RespBeanEnum.LOGINVO_ERROR);
        }
        User user = userMapper.selectById(mobile);
        if (null == user){
            return RespBean.error(RespBeanEnum.LOGINVO_ERROR);
        }
        if (!MD5Util.formPassToDBPass(password,user.getSlat()).equals(user.getPassword())){
            return RespBean.error(RespBeanEnum.LOGINVO_ERROR);
        }
        //生成cookie
        String ticket = UUIDUtil.uuid();
        //用户信息存入redis
        redisTemplate.opsForValue().set("user:"+ticket,user);
       // request.getSession().setAttribute(ticket,user);
        CookieUtil.setCookie(request,response,"ticket",ticket);
        return RespBean.success();
    }
}

service添加新方法,获取用户

//获取用户值
@Override
public User getUserByCookie(String userTicket, HttpServletRequest request, HttpServletResponse response) {
    User user = (User)redisTemplate.opsForValue().get("user:" + userTicket);
    if (user != null){
        CookieUtil.setCookie(request,response,"userTicket",userTicket);
    }
    return user;
}

此时即可完成单点登录。

还可以优化一下,因为每次都需要判断用户是否登录,所以在进行接收参数之前就进行判断

//自定义用户参数
@Component
public class UserArgumentResolver implements HandlerMethodArgumentResolver {
    @Autowired
    private IUserService userService;
    //判断类型是不是uaer类型
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
    //获取参数类型  
        Class<?> clazz = parameter.getParameterType();
        return clazz == User.class;
    }
    //进行ticket判断
    @Override
    public Object resolveArgument(MethodParameter parameter,
                                  ModelAndViewContainer mavContainer,
                                  NativeWebRequest webRequest,
                                  WebDataBinderFactory binderFactory) throws Exception {
        HttpServletRequest request =
                webRequest.getNativeRequest(HttpServletRequest.class);
        HttpServletResponse response =
                webRequest.getNativeResponse(HttpServletResponse.class);
        String ticket = CookieUtil.getCookieValue(request, "userTicket");
        if (StringUtils.isEmpty(ticket)) {
            return null;
        }
        //获取redis数据
        return userService.getUserByCookie(ticket, request, response);
    }
}
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    @Autowired
    private UserArgumentResolver userArgumentResolver;
    //自定义参数解析器
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(userArgumentResolver);
    }

}
@Controller
@RequestMapping("/goods")
public class GoodsController {
    @Autowired
    private IUserService userService;
    @RequestMapping("/toList")
    public String toList(Model model,User user){
        model.addAttribute("user",user);
        return "goodsList";
    }

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐