java基于token验证之登陆验证

时间:2024-03-12 15:58:09

对于前后端分离的项目来说session来判断是否登陆实现比较困难,token是比较好的方式。

大概流程:

 1.用户登陆,若成功则后台生成一个token,并把此token返回给客户端浏览器

2.客户端接收到token后,每次请求都要把此token放到header中发给后段

3.后段使用拦截器判断token的正确性和实效性。

以下是具体代码:

Token工具类:

package com.zsd.analyst.util;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
* JWT工具类
*
* @author SuperMu
* @Date: 2018/8/17 15:26
*/
public class JwtTokenUtil implements Serializable {


private static final long serialVersionUID = 6065288623015212853L;

private static final String CLAIM_KEY_CREATED = "created";
private static final String CLAIM_KEY_ID = "jti";


//#过期时间(秒) 目前有效期为10天
private static final long expiration = 15 * 60 * 1000;

/**
* token秘钥,请勿泄露,请勿随便修改
*/
private static final String secret = "JCKLJSDToasdlfj";


/**
* 从数据声明生成令牌
*
* @param claims 数据声明
* @return 令牌
*/
private static String generateToken(Map<String, Object> claims) {
Date expirationDate = new Date(System.currentTimeMillis() + expiration * 1000L);
return Jwts.builder().setClaims(claims).setExpiration(expirationDate).signWith(SignatureAlgorithm.HS512, secret).compact();
}

/**
* 从令牌中获取数据声明
*
* @param token 令牌
* @return 数据声明
*/
private static Claims getClaimsFromToken(String token) {
Claims claims;
try {
claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
} catch (Exception e) {
claims = null;
}
return claims;
}

/**
* 生成令牌
*
* @return 令牌
*/
public static String generateToken(Long userId) {
Map<String, Object> claims = new HashMap<String, Object>(2);
//claims.put(CLAIM_KEY_USERNAME, userDetails.getUsername());
claims.put(CLAIM_KEY_CREATED, new Date());
claims.put(CLAIM_KEY_ID, userId);
return generateToken(claims);
}


/**
* 从令牌中获取用户ID
*
* @param token 令牌
* @return id
*/
public static Long getIdFromToken(String token) {
Long id;
try {
Claims claims = getClaimsFromToken(token);
id = Long.valueOf(claims.getId());
} catch (Exception e) {
id = null;
}
return id;
}


/**
* 判断令牌是否过期
*
* @param token 令牌
* @return 是否过期
*/
public static Boolean isTokenExpired(String token) {
try {
Claims claims = getClaimsFromToken(token);
Date expiration = claims.getExpiration();
return expiration.before(new Date());
} catch (Exception e) {
return false;
}
}

/**
* 刷新令牌
*
* @param token 原令牌
* @return 新令牌
*/
public static String refreshToken(String token) {
String refreshedToken;
try {
Claims claims = getClaimsFromToken(token);
claims.put("created", new Date());
refreshedToken = generateToken(claims);
} catch (Exception e) {
refreshedToken = null;
}
return refreshedToken;
}

/**
* 验证令牌
*
* @param token 令牌
* @param userId 用户Id
* @return 是否有效
*/
public static Boolean validateToken(String token, Long userId) {
Long id = getIdFromToken(token);
return (id.equals(userId) && !isTokenExpired(token));
}

public static void main(String[] args) {

System.out.println("得到用户id=="+generateToken(1L));
}
}

注册拦截器:
package com.zsd.analyst.util;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;


//@Configuration
public class LoginAdapter implements WebMvcConfigurer {
//解决跨域问题
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedHeaders("Content-Type","X-Requested-With","accept,Origin","Access-Control-Request-Method","Access-Control-Request-Headers","token")
.allowedMethods("*")
.allowedOrigins("*")
//是否允许使用cookie
.allowCredentials(true);
}




@Autowired
private TokenRefreshFilter tokenRefreshFilter;


// 这个方法是用来配置静态资源的,比如html,js,css,等等
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
}



// 这个方法用来注册拦截器,我们自己写好的拦截器需要通过这里添加注册才能生效
@Override
public void addInterceptors(InterceptorRegistry registry) {
System.out.println("进入拦截器");
//addPathPatterns是表明拦截哪些请求
//excludePathPatterns是对哪些请求不做拦截
registry.addInterceptor(tokenRefreshFilter).addPathPatterns("/**").excludePathPatterns("/login").excludePathPatterns("/backLogin");
}


}


拦截器:
package com.zsd.analyst.util;

import com.alibaba.fastjson.JSONObject;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;

//@Component
public class TokenRefreshFilter implements HandlerInterceptor {

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
response.setCharacterEncoding("UTF-8");
Cookie[] tokens = request.getCookies();
String token = null;
for (Cookie cookie : tokens) {
if (cookie.getName().equals("token")){
token = cookie.getValue();
}
}
if (null == token) {
Map<String, Object> map = new HashMap<>();
map.put("data", "token is null");
map.put("code", "401");
response.getWriter().write(JSONObject.toJSONString(map));
return false;
} else {
boolean result = JwtTokenUtil.isTokenExpired(token);

if (result) {
//更新存储的token信息
response.setHeader("token", JwtTokenUtil.refreshToken(token));
return true;
}

return true;
}
}
}

cookieUtil:
package com.zsd.analyst.util;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class CookieUtil {
public static final String TOKEN_NAME = "token";
public static final int TOKEN_EXPIRESECONDS = 1800;
//往浏览器写入cookie信息
public static void addCookie(HttpServletResponse response, String cookieName, String cookieValue, int expireSeconds){
Cookie cookie = new Cookie(cookieName,cookieValue);
cookie.setDomain("localhost");//作用域,用户请求哪个域名的时候回带上该cookie信息,域名应该是nginx域名或者zuul域名
cookie.setPath("/");
cookie.setMaxAge(expireSeconds);
response.addCookie(cookie);
}
//从请求中获取指定Cookie的信息.
public static String getCookie(HttpServletRequest request, String cookieName){
Cookie[] cookies = request.getCookies();
if(cookies==null || cookies.length==0){
//请求中没有cookie的信息,不需要做任何的逻辑
return null;
}
for(Cookie cookie:cookies){
if(cookie.getName().equals(cookieName)){
return cookie.getValue();
}
}
return null;
}
}
登录后把token加到cookie中
CookieUtil.addCookie(response,"token",JwtTokenUtil.generateToken(accountInfo.getId()),CookieUtil.TOKEN_EXPIRESECONDS);