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

叁歲伎倆 2023-07-15 09:52 23阅读 0赞

简介

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








1

2

3

4

5

6

<!— 生成token —>

<dependency>

 <groupId>io.jsonwebtoken</groupId>

 <artifactId>jjwt</artifactId>

 <version>0.9.0</version>

</dependency>

开发步骤

1、创建token库

201982384808369.jpg?201972384818uploading.4e448015.gif转存失败重新上传取消201982384808369.jpg_201972384818

2、创建token实体类








1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

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的三个方法(添加、查询、修改)








1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

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、创建拦截器








1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

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>6060243){

  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、配置拦截器








1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

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层








1

2

3

4

@RequestMapping(“/getlogin”)

public Object login(@Param(“..”) LoginQueryForm loginForm) {

return userViewService.login(loginForm);

}

serrvice层








1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

@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操作








1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

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








1

2

3

4

5

6

7

8

9

10

11

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

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

您可能感兴趣的文章:

  • SpringBoot使用token简单鉴权的具体实现方法
  • springboot整合token的实现代码
  • SpringBoot集成FastDFS+Nginx整合基于Token的防盗链的方法
  • spring boot+jwt实现api的token认证详解
  • SpringBoot集成JWT实现token验证的流程

发表评论

表情:
评论列表 (有 0 条评论,23人围观)

还没有评论,来说两句吧...

相关阅读