token过期时间分平台(web和app)设置方法

token分平台设置方法

本文介绍了Spring下的登录和鉴权机制的主要方法以及 token认证的主要流程,并介绍在spring中web端和APP端设置不同token过期时间的实现方法。主要基于SpringBoot+springSecurity+JWT框架实现。

一、应用场景

同一系统的跨平台操作,基于用户习惯,web端和app端用户使用时间长短常常不同,统一过长时间容易造成服务器资源浪费,统一过短使得用户未操作完就登录过期。因此,为更便于用户使用,分平台设置token过期时间能提升用户体验。

二、登录方法和token鉴权

要分平台设置token过期时间,首先要了解SpringSecurity登录流程的主要方法和token生成。

1、登录流程

登录-->校验用户名、密码、验证码-->redis存储登录用户信息-->生成token(JWT)-->返回token

// 仅展示关键语句

java 复制代码
@PostMapping("/login")
public AjaxResult login(@RequestBody LoginBody loginBody)
{
    AjaxResult ajax = AjaxResult.success();
    // 生成令牌
    String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),
            loginBody.getUuid(),loginBody.getClientPubKey(), loginBody.getPlatForm());
    ajax.put(Constants.TOKEN, token);
    return ajax;
}
java 复制代码
public String login(String username, String aes_password, String code, String uuid, String clientPubKey, String platForm) {



// 验证用户名密码

authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));



LoginUser loginUser = (LoginUser) authentication.getPrincipal();



// 生成token
loginUser.setPlatForm(platForm);
return tokenService.createToken(loginUser);

}

2、JWT

JWT是一种基于 Token 的认证授权机制, 可用于创建token。

Token = Head+info+sign

Head: 编码方式

Info:用户信息,包括用户名等自定义信息

Sign:签名

如下所示:

java 复制代码
Map<String, Object> claims = new HashMap<>();
claims.put(Constants.LOGIN_USER_KEY, token);
claims.put(Constants.JWT_USERID, loginUser.getUserId());
claims.put(Constants.JWT_USERNAME, loginUser.getUsername());



private String createToken(Map<String, Object> claims)
{
    String token = Jwts.builder()
            .setClaims(claims)
            .signWith(SignatureAlgorithm.HS512, secret).compact();
    return token;
}

3、Token鉴权

登录后返回的token存于前端缓存,每次请求时放于请求头,经过拦截器时解析token,并verifyToken方法校验token是否有效或过期,同时redreshToken延长过期时间(本次为活跃)。

// 校验

java 复制代码
public void verifyToken(LoginUser loginUser)
{
    long expireTime = loginUser.getExpireTime();
    long currentTime = System.currentTimeMillis();

    if(loginUser.getPlatForm().equals("pc")){
        if (expireTime - currentTime <= MILLIS_MINUTE_TEN_PC)
        {
            refreshToken(loginUser);
        }

    }else if(loginUser.getPlatForm().equals("app")) {
        if (expireTime - currentTime <= MILLIS_MINUTE_TEN_APP) {
            refreshToken(loginUser);
        }
    }
}

// 更新过期时间

java 复制代码
public void refreshToken(LoginUser loginUser)
{
    if(loginUser.getPlatForm().equals("pc")){
        expireTime = pcExpireTime;
    }else if(loginUser.getPlatForm().equals("app")){
        expireTime = appExpireTime;
    }
    loginUser.setLoginTime(System.currentTimeMillis());
    loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE);
    // 根据uuid将loginUser缓存
    String userKey = getTokenKey(loginUser.getToken());
    redisCache.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES);
}

三、实现方法

1、配置文件

Pc端过期时间59min,app端3天

java 复制代码
# token配置
token:
  # 令牌自定义标识
  header: Authorization
  # 令牌密钥
  secret: abcdefghijklmnopqrstuvwxyz
  # 令牌有效期(默认59分钟; APP端3天)
  expireTime:
    defaultExpireTime: 59
    pcExpireTime: 59
    appExpireTime: 4320

2、登录信息实体类

增加平台信息

src/main/java/com/common/core/domain/model/LoginBody.java

src/main/java/com/common/core/domain/model/LoginUser.java

java 复制代码
public class LoginBody {



//  ****其他省略

/**
 * 登录平台: 手机端='app',PC端='pc'
 */
private String platForm;
public String getPlatForm() {
    return platForm;
}
public void setPlatForm(String platForm) {
    this.platForm = platForm;
}

}

3、登录方法

(1)login的controller层方法

生成token的方法参数加上平台信息

src/main/java/com/web/controller/system/SysLoginController.java

java 复制代码
@PostMapping("/login")
public AjaxResult login(@RequestBody LoginBody loginBody)
{
    AjaxResult ajax = AjaxResult.success();
    // 生成令牌
    String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),
            loginBody.getUuid(),loginBody.getClientPubKey(), loginBody.getPlatForm());
    ajax.put(Constants.TOKEN, token);
    return ajax;
}

(2) 登录信息检验及token生成

src/main/java/com/inspur/framework/web/service/SysLoginService.java

// 基于SpringSecurity的验证方法,修改返回的登录用户信息,可以在返回后再人工设置。

java 复制代码
public String login(String username, String aes_password, String code, String uuid, String clientPubKey, String platForm) {

// 仅仅展示重要关键语句



// 验证用户名密码

authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));

// 返回登录信息

LoginUser loginUser = (LoginUser) authentication.getPrincipal();



// 生成token
loginUser.setPlatForm(platForm);
return tokenService.createToken(loginUser);

}
java 复制代码
private String createToken(Map<String, Object> claims)
{
    String token = Jwts.builder()
            .setClaims(claims)
            .signWith(SignatureAlgorithm.HS512, secret).compact();
    return token;
}

(3)Token验证鉴权及更新

src/main/java/com/inspur/common/service/TokenService.java

// 用户每次请求将token信息存放于请求头,经过拦截器拦截。

java 复制代码
@Component
public class TokenService
{

// 令牌有效期(默认30分钟)

@Value("${token.expireTime.defaultExpireTime}")
private int expireTime;

@Value("${token.expireTime.pcExpireTime}")
private int pcExpireTime;
@Value("${token.expireTime.appExpireTime}")
private int appExpireTime;



//pc端-距离20分钟时刷新token过期时间
private static final Long MILLIS_MINUTE_TEN_PC = 20 * 60 * 1000L;
//app端-距离1天时刷新token过期时间
private static final Long MILLIS_MINUTE_TEN_APP = 24 * 60 * 60 * 1000L;



public void verifyToken(LoginUser loginUser)
{
    long expireTime = loginUser.getExpireTime();
    long currentTime = System.currentTimeMillis();

    if(loginUser.getPlatForm().equals("pc")){
        if (expireTime - currentTime <= MILLIS_MINUTE_TEN_PC)
        {
            refreshToken(loginUser);
        }
    }else if(loginUser.getPlatForm().equals("app")) {
        if (expireTime - currentTime <= MILLIS_MINUTE_TEN_APP) {
            refreshToken(loginUser);
        }
    }
}
java 复制代码
public void refreshToken(LoginUser loginUser)
{
    if(loginUser.getPlatForm().equals("pc")){
        expireTime = pcExpireTime;
    }else if(loginUser.getPlatForm().equals("app")){
        expireTime = appExpireTime;
    }

    loginUser.setLoginTime(System.currentTimeMillis());
    loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE);
    // 根据uuid将loginUser缓存
    String userKey = getTokenKey(loginUser.getToken());
    redisCache.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES);
}

}

4、前端传递平台信息

(1)web端(基于Vue)

登录传递平台信息:platForm='pc'

src/store/modules/user.js

javascript 复制代码
// 登录
Login({commit}, userInfo) {
  const username = userInfo.username.trim()
  const password = userInfo.password
  const code = userInfo.code
  const uuid = userInfo.uuid
  const platForm = 'pc'
  return new Promise((resolve, reject) => {
    getPublicKey(username).then(res => {
      if (res.code === 200) {
        let result = encryptData(res.data, password);
        let aes_password = result.encryptedData;
        login(username, aes_password, code, uuid,result.clientKey,platForm).then(res => {
          setToken(res.token)
          commit('SET_TOKEN', res.token)
          resolve()
        }).catch(error => {
          reject(error)
        })
      }
    })
  })
},

src/api/login.js

javascript 复制代码
export function login(username, password, code, uuid,clientPubKey) {
  const platForm = 'pc'
  const data = {
    username,
    password,
    code,
    uuid,
    clientPubKey,
    platForm
  }
  return request({
    url: '/login',
    method: 'post',
    data: data
  })
}

(2)app端(基于uniapp)

api/login.js

javascript 复制代码
// 登录方法
export function login(username, password, code, uuid) {
  let platForm = 'app'
  const data = {
    username,
    password,
    code,
    uuid,
    platForm
  }
  return request({
    'url': '/appLogin',
    headers: {
      isToken: false
    },
    'method': 'post',
    'data': data
  })
}
相关推荐
lichong9511 天前
Android studio 修改包名
android·java·前端·ide·android studio·大前端·大前端++
lichong9511 天前
Git 检出到HEAD 再修改提交commit 会消失解决方案
java·前端·git·python·github·大前端·大前端++
@yanyu6661 天前
Tomcat安装与HTML响应实战
java·tomcat·html
Chen-Edward1 天前
有了Spring为什么还有要Spring Boot?
java·spring boot·spring
陈小桔1 天前
idea中重新加载所有maven项目失败,但maven compile成功
java·maven
小学鸡!1 天前
Spring Boot实现日志链路追踪
java·spring boot·后端
xiaogg36781 天前
阿里云k8s1.33部署yaml和dockerfile配置文件
java·linux·kubernetes
逆光的July1 天前
Hikari连接池
java
微风粼粼1 天前
eclipse 导入javaweb项目,以及配置教程(傻瓜式教学)
java·ide·eclipse
番茄Salad1 天前
Spring Boot临时解决循环依赖注入问题
java·spring boot·spring cloud