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

网友投稿 291 2022-12-30


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

简介

公司新项目,需要做移动端(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包

io.jsonwebtoken

jjwt

0.9.0

开发步骤

1、创建token库

2、创建token实体类

package com.prereadweb.user.entity;

import lombok.Data;

/**

* @Description: Token实体类

* @author: Yangxf

* @date: 2019/4/14 12:53

*/

@Data

public 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

*/

@Mapper

public 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

*/

@Configuration

public 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 login(LoginQueryForm loginForm) {

Map 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 operateToKen(Map 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.gekWcNQWtSession();

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


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:微服务网关重启接口变慢(网关调用微服务错误)
下一篇:系统接口设计编写目的(接口设计思想)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~