首页 > 编程 > Java > 正文

SpringBoot框架集成token实现登录校验功能

2019-11-26 08:41:12
字体:
来源:转载
供稿:网友

简介

公司新项目,需要做移动端(Android和IOS),登录模块,两个移动端人员提出用token来校验登录状态,一脸懵懵的,没做过,对于token的基本定义都模棱两可,然后查资料查查查,最终OK完成,写篇博客记录一下

思路:

1、基于session登录

基于session的登录(有回话状态),用户携带账号密码发送请求向服务器,服务器进行判断,成功后将用户信息放入session,用户发送请求判断session中是否有用户信息,有的话放行,没有的话进行拦截,但是考虑到时App产品,牵扯到要判断用户的session,需要sessionID,还要根据sessionId来获取session,在进行校验,还有sessionId的一个存储等等,所以没考虑用session

2、基于token登录

基于token的登录,是不存在回话状态,大概思路,在用户初次等路的时候,校验用户账号密码,成功后给其生成一个token,token=用户ID+时间戳+过期时间+一个自己平台规定的签名,使用jjwt生成一个令牌,然后对其进行存库,用户每次访问接口,都会在头部Headers中带上token,后来拦截器对其进行拦截,如果token为空或错误则让其登录,如果有token,获取token进行其解析,取出里面的用户ID,根据用户ID查询数据库中所存token,判断其是否正确,正确使其登录,错误则提示登录,大致思路就是这样,下面开始代码

导入jar包

<!-- 生成token --><dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.0</version></dependency>

开发步骤

1、创建token库

2、创建token实体类

package com.prereadweb.user.entity; import lombok.Data; /** * @Description: Token实体类 * @author: Yangxf * @date: 2019/4/14 12:53 */@Datapublic class TokenEntity {  /* tokenId */ private Long id;  /* 用户ID */ private Long userId;  /* 刷新时间 */ private int buildTime;  /* token */ private String token; }

3、编写token的三个方法(添加、查询、修改)

package com.prereadweb.user.mapper; import com.prereadweb.user.entity.TokenEntity;import org.apache.ibatis.annotations.Mapper; /** * @Description: Token数据库持久层接口 * @author: Yangxf * @date: 2019/4/14 13:00 */@Mapperpublic interface TokenMapper {  /* 添加token */ void addToken(TokenEntity token);  /* 修改token */ void updataToken(TokenEntity token);  /* 查询token */ TokenEntity findByUserId(Long userId); }

4、创建拦截器

package com.prereadweb.user.interceptor; import com.prereadweb.user.entity.TokenEntity;import com.prereadweb.user.mapper.TokenMapper;import io.jsonwebtoken.Claims;import io.jsonwebtoken.Jwts;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.servlet.HandlerInterceptor;import org.springframework.web.servlet.ModelAndView; import javax.servlet.ServletOutputStream;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.util.Date; /** * @Description:拦截器 * @author: Yangxf * @date: 2019/4/14 12:58 */public class LoginInterceptor implements HandlerInterceptor {  @Autowired protected TokenMapper tokenMapper; //提供查询 @Override public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)   throws Exception {} @Override public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)   throws Exception {} @Override public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {  //此处为不需要登录的接口放行  if (arg0.getRequestURI().contains("/login") || arg0.getRequestURI().contains("/register") || arg0.getRequestURI().contains("/error") || arg0.getRequestURI().contains("/static")) {   return true;  }  //权限路径拦截  //PrintWriter resultWriter = arg1.getOutputStream();  // TODO: 有时候用PrintWriter 回报 getWriter() has already been called for this response  //换成ServletOutputStream就OK了  arg1.setContentType("text/html;charset=utf-8");  ServletOutputStream resultWriter = arg1.getOutputStream();  final String headerToken=arg0.getHeader("token");  //判断请求信息  if(null==headerToken||headerToken.trim().equals("")){   resultWriter.write("你没有token,需要登录".getBytes());   resultWriter.flush();   resultWriter.close();   return false;  }  //解析Token信息  try {   Claims claims = Jwts.parser().setSigningKey("preRead").parseClaimsJws(headerToken).getBody();   String tokenUserId=(String)claims.get("userId");   long iTokenUserId = Long.parseLong(tokenUserId);   //根据客户Token查找数据库Token   TokenEntity myToken= tokenMapper.findByUserId(iTokenUserId);    //数据库没有Token记录   if(null==myToken) {    resultWriter.write("我没有你的token?,需要登录".getBytes());    resultWriter.flush();    resultWriter.close();    return false;   }   //数据库Token与客户Token比较   if( !headerToken.equals(myToken.getToken()) ){    resultWriter.print("你的token修改过?,需要登录");    resultWriter.flush();    resultWriter.close();    return false;   }   //判断Token过期   Date tokenDate= claims.getExpiration();   int overTime=(int)(new Date().getTime()-tokenDate.getTime())/1000;   if(overTime>60*60*24*3){    resultWriter.write("你的token过期了?,需要登录".getBytes());    resultWriter.flush();    resultWriter.close();    return false;   }   } catch (Exception e) {   resultWriter.write("反正token不对,需要登录".getBytes());   resultWriter.flush();   resultWriter.close();   return false;  }  //最后才放行  return true; } }

5、配置拦截器

package com.prereadweb.user.config; import com.prereadweb.user.interceptor.LoginInterceptor;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.InterceptorRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; /** * @Description: 拦截器配置 * @author: Yangxf * @date: 2019/4/14 13:09 */@Configurationpublic class LoginConfiguration implements WebMvcConfigurer {  /**  * @Function: 这个方法才能在拦截器中自动注入查询数据库的对象  * @author: YangXueFeng  * @Date:  2019/4/14 13:10  */ @Bean LoginInterceptor loginInterceptor() {  return new LoginInterceptor(); }  /**  * @Function: 配置生成器:添加一个拦截器,拦截路径为login以后的路径  * @author: YangXueFeng  * @Date:  2019/4/14 13:10  */ @Override public void addInterceptors(InterceptorRegistry registry ){  registry.addInterceptor(loginInterceptor()).addPathPatterns("/**").excludePathPatterns("/login", "/register", "/static"); }}

6、登录

controller层

 @RequestMapping("/getlogin") public Object login(@Param("..") LoginQueryForm loginForm) {  return userViewService.login(loginForm); }

serrvice层

@Override public Map<String, Object> login(LoginQueryForm loginForm) {   Map<String, Object> map = new HashMap<>();  //手机验证码登录  if(!Util.isEmpty(loginForm.getPhoneCode())) {   return phoneCodeLogin(loginForm, map);  }  //判断用户信息为空  if (Util.isEmpty(loginForm.getPhone()) || Util.isEmpty(loginForm.getLoginPwd())) {   return checkParameter(map);  }  //根据手机号查询user对象  UserEntity user = userMapper.getUser(loginForm.getPhone());   //判断用户不存在  if (Util.isEmpty(user)) {   map.put("code", UserStatusEnum.USER_NON_EXISTENT.intKey());   map.put("msg", UserStatusEnum.USER_NON_EXISTENT.value());   return map;  }  /* 判断密码 */  if(!MD5Util.string2MD5(loginForm.getLoginPwd()).equals(user.getLoginPwd())){   map.put("code", UserStatusEnum.PWD_ERROR.intKey());   map.put("msg", UserStatusEnum.PWD_ERROR.value());   return map;  }   //根据数据库的用户信息查询Token  return operateToKen(map, user, user.getId()); }

token操作

private Map<String, Object> operateToKen(Map<String, Object> map, UserEntity user, long userId) {  //根据数据库的用户信息查询Token  TokenEntity token = tokenmapper.findByUserId(userId);  //为生成Token准备  String TokenStr = "";  Date date = new Date();  int nowTime = (int) (date.getTime() / 1000);  //生成Token  TokenStr = creatToken(userId, date);  if (null == token) {   //第一次登陆   token = new TokenEntity();   token.setToken(TokenStr);   token.setBuildTime(nowTime);   token.setUserId(userId);   token.setId(Long.valueOf(IdUtils.getPrimaryKey()));   tokenmapper.addToken(token);  }else{   //登陆就更新Token信息   TokenStr = creatToken(userId, date);   token.setToken(TokenStr);   token.setBuildTime(nowTime);   tokenmapper.updataToken(token);  }  UserQueryForm queryForm = getUserInfo(user, TokenStr);  /* 将用户信息存入session */  /*SessionContext sessionContext = SessionContext.getInstance();  HttpSession session = sessionContext.getSession();  httpSession.setAttribute("userInfo", user);*/  //返回Token信息给客户端  successful(map);  map.put("data", queryForm);  return map; }

生成token

private String creatToken(Long userId, Date date) {  SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;  JwtBuilder builder = Jwts.builder().setHeaderParam("typ", "JWT") // 设置header    .setHeaderParam("alg", "HS256").setIssuedAt(date) // 设置签发时间    .setExpiration(new Date(date.getTime() + 1000 * 60 * 60))    .claim("userId",String.valueOf(userId) ) // 设置内容    .setIssuer("lws")// 设置签发人    .signWith(signatureAlgorithm, "签名"); // 签名,需要算法和key  String jwt = builder.compact();  return jwt; }

至此,token登录OK

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持武林网。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表