SpringMVC集成jwt
场景:接手新的平台没有加入安全框架,导致APP在集成对接的过程中,每次发送请求后都要调用一次登录接口获取Session,根据获得的id去请求相关的API接口,我不清楚为何这样设计,想的就是拿到授权码,在一定时间内可以凭授权码进行API的调用。
JWT的流程图:
gradle导入jwt包
compile 'com.auth0:java-jwt:2.2.0'
jwt工具类
package unis.cloud.api.tool;
import java.util.HashMap;
import java.util.Map;
import com.auth0.jwt.JWTSigner;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.internal.com.fasterxml.jackson.databind.ObjectMapper;
public class JWTTool {
private static final String SECRET = "XX#$%()(#*!()!KL<><MQLMNQNQJQK sdfkjsdrow32234545fdf>?N<:{LWPW";
private static final String EXP = "exp";
private static final String PAYLOAD = "payload";
//加密,传入一个对象和有效期
public static <T> String sign(T object, long maxAge) {
try {
final JWTSigner signer = new JWTSigner(SECRET);
final Map<String, Object> claims = new HashMap<String, Object>();
ObjectMapper mapper = new ObjectMapper();
String jsonString = mapper.writeValueAsString(object);
claims.put(PAYLOAD, jsonString);
claims.put(EXP, System.currentTimeMillis() + maxAge);
return signer.sign(claims);
} catch(Exception e) {
return null;
}
}
//解密,传入一个加密后的token字符串和解密后的类型
public static<T> T unsign(String jwt, Class<T> classT) {
final JWTVerifier verifier = new JWTVerifier(SECRET);
try {
final Map<String,Object> claims= verifier.verify(jwt);
if (claims.containsKey(EXP) && claims.containsKey(PAYLOAD)) {
long exp = (Long)claims.get(EXP);
long currentTimeMillis = System.currentTimeMillis();
if (exp > currentTimeMillis) {
String json = (String)claims.get(PAYLOAD);
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(json, classT);
}
}
return null;
} catch (Exception e) {
return null;
}
}
}
生成token
public void doLogin(@P("userName") String userName,@P("mobilePhone") String mobilePhone,@P("passWord") String password) {
if ((isEmpty(userName)&& isEmpty(mobilePhone)) || isEmpty(password)) {
setRespData(-1, "参数异常!", null);
return;
}
User searchUser = new User();
searchUser.user_name = userName;
searchUser.mobile_phone = mobilePhone;
User user = userService.selectOneBy(searchUser, null, null, null);
if (user==null) {
setRespData(-2, "账户信息输入有误,请验证后重试!", null);
return;
}
int ret = userService.checkLogin(password, user.password_hash, user.password_salt);
if (ret !=1) {
setRespData(-3, "密码不正确,请验证后重试!", null);
return;
}
searchUser.id = user.id;
//给用户jwt加密生成token 30分钟
String token = JWTTool.sign(searchUser, 60L* 1000L* 30L);
HttpSession session = getContext().getReq().getSession();
session.setAttribute("userId", user.id);
setRespAttr("token", token);
setRespData(0, null, null);
return;
}
在过滤器中拦截请求,并校验token
package unis.cloud.api.config;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSONObject;
import unis.cloud.api.tool.JWTTool;
import unis.cloud.api.user.User;
//过滤器,加入jwt验证
public class TokenFilter implements Filter{
private static Logger logger = LoggerFactory.getLogger(TokenFilter.class);
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletResponse hpResponse = (HttpServletResponse) response;
HttpServletRequest hpRequest = (HttpServletRequest) request;
String path = ((HttpServletRequest) request).getRequestURI();
if (path.equals("/")|| path.startsWith("/login/")) {
chain.doFilter(request, response);
return;
}
hpResponse.setCharacterEncoding("utf-8");
HttpSession session = hpRequest.getSession();
String userId = String.valueOf(session.getAttribute("userId"));
logger.info("拦截的用户session信息:"+userId);
String token = hpRequest.getParameter("token");
if (token!=null) {
User user = JWTTool.unsign(token, User.class);
logger.info("拦截的根据token解密的用户信息:"+user);
if (user.id.equals(userId)) {
chain.doFilter(request, response);
}
}
ResponseData responseData = ResponseData.forbidden();
responseMessage(hpResponse,hpResponse.getWriter(),responseData);
return;
}
//请求不通过,返回错误信息给客户端
private void responseMessage(HttpServletResponse response, PrintWriter out, ResponseData responseData) {
responseData = ResponseData.forbidden();
response.setContentType("application/json; charset=utf-8");
String json = JSONObject.toJSONString(responseData);
out.print(json);
out.flush();
out.close();
}
@Override
public void destroy() {
// TODO Auto-generated method stub
}
}
拦截器的使用,需要在web.xml中配置相关信息
<filter>
<filter-name>TokenFilter</filter-name>
<filter-class>unis.cloud.api.config.TokenFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>TokenFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
问题
拿到token后前端进行获取使用,假如token的时效是30分钟,前端在31分钟后拿着相同的token请求接口信息的时候会出现token失效的问题,怎么才能保证用户在连续31分钟使用的时候token自动更新,而且长时间不操作的情况下,31分钟正常提示token失效?
评论