使用jwt实现登录功能

一、什么是jwt

1.什么是session

要想知道什么是jwt,就要先知道什么是session,可以这样理解session,处于安全问题,有一些数据需要保存在服务端,服务端根据客户端的sessionId可以识别到它的session,然后进行数据的处理。
session一般存储一些简单,并且比较重要的信息,例如用户id,用户登录状态,权限等。

使用jwt实现登录功能_第1张图片

注意,如果用户禁用了cookie,那么session也就无法使用,因为session使用cookie中携带的唯一id才能在服务器中找到

2.什么是jwt?

jwt全程是json web token。是由用户以用户名、密码登录,服务端验证后,会生成一个token,返回给客户端,客户端在下次访问的过程中携带这个token,服务端责每次验证这个token。
使用jwt实现登录功能_第2张图片

3.为什么使用jwt而不使用session

  1. session是将客户端数据储存在服务器的内存,当客服端的数据过多,服务器的内存开销大;
  2. session的数据储存在某台服务器,在分布式的项目中无法做到共享;
  3. jwt的安全性更好。

总而言之,如果使用了分布式,切只能在session和jwt里面选的时候,就一定要选jwt。

二、jwt原理

1. header 头:

包含令牌的类型和使用的签名算法

{
	"alg":"HS625", // 签名算法
	"type":"JWT" // 令牌类型
}

将请求头进行base64加密就构成了第一部分

2.payload 荷载

荷载就是装载数据的地方,包含声明(有关用户实体和其他数据的声明),使用Base64进行编码,
可以把payload荷载想象成session的数据,session虽然存放在服务器内存,也要防止一些意外,比如有工作人员监守自盗盗取密码,因此,session里面不可以存放敏感信息

{
	"username": "zhangsan",
	"dataAuth": "beijing"
}

3.signature 签名

将header和payload经过base64加密后的数据经过加盐后进行二次加密。
盐值仅仅保存在服务器端,不能泄露,如果泄露容易导致客户端自己签发token,例如:即使没有经过登录步骤,知道用户名username,用自己签发token去访问一些数据权限敏感的数据。

三、使用实现登录

1.引入依赖

implementions('io.jsonwebtoken:jjwt:0.7.0')

2.准备配置

# token私钥,储存在只有签发和解析token的服务端
jwt.secret=123456
# 过期时间,单位为毫秒,这里是24*60*60*1000,24小时内有效
jwt.expire=86400000

3.创建和解析JWT的工具类

@ConfigurationProperties(prefix = "jwt")
@Component
@Data
public class JwtConfig {

	private String secret;

    private long expire;

    /**
     * 签发jwt
     *
     * @param user
     * @return
     */
    public String createJWT(User user) {
        Date date = new Date();
        Date expireDate = new Date(date.getTime() + expire);
        Map<String, Object> claims = new HashMap<>();
        claims.put("name", user.getUsername());
        claims.put("id", user.getId());
        String jwt = Jwts.builder()
                // 设置装载内容
                .setClaims(claims)
                // 签发时间
                .setIssuedAt(date)
                // 过期时间
                .setExpiration(expireDate)
                // jwt主体,用来存放jwt的所有人,可以存用户id或者角色id
                .setSubject(user.getName())
                .compact();
        return jwt;
    }
    
    /**
     * 解析JWT
     *
     * @param jwt
     * @return
     */
    public Claims parseJWT(String jwt) {
        Claims claims = Jwts.parser().setSigningKey(secret).parseClaimsJwt(jwt).getBody();
        return claims;
    }
    
}

4.登录时签发token

    @RequestMapping("login")
    public Map<String, Object> login(@RequestParam(name = "name") String name, @RequestParam(name = "passWord") String passWord) {
        User user = userService.findByUsernameAndPassword(name, passWord);
        if (null == user ) {
            throw new ControllerException("501", "用户名或密码错误");
        }
        String token = jwtConfig.createJWT(user);
        map.put("token", token);
        return map;
    }

5.过滤器及其配置类

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Resource
    private LoginInterceptor loginInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginInterceptor).addPathPatterns("/**");
    }
}
@Component
public class LoginInterceptor extends HandlerInterceptorAdapter {
    
    @Resource
    private JwtConfig jwtConfig;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        String url = request.getRequestURI();
        // 如果包含login,则直接去验证用户名密码,不需要去验证token,可以利用这里设置白名单
        if (url.contains("/login")) {
            return true;
        }
        String token = request.getHeader(jwtConfig.getHeader());
        if (StringUtils.isEmpty(token)) {
            token = request.getParameter(jwtConfig.getHeader());
        }
        if (null == token || token.isEmpty()) {
            return false;
        }
        Claims claims = jwtConfig.parseJWT(token);
		String userName = claims.get("name", String.class);
        request.setAttribute("userName", subject);
        return true;
    }


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return true;
    }
}

你可能感兴趣的:(jwt)