现在越来越多的登录方式都用到了token作为用户登录令牌,所以实现了一个token生成和校验案例。

缺点:该实现方式token是存储在内存中,不适合分布式项目,如需改为分布式项目部署,可把token存储在redis中,其中的实现原理还是保持不变。

一)token编码工具类

package com.oysept.token.utils;

/**

* token编码工具类

* @author ouyangjun

*/

public class TokenEncryptUtils {

// 编码密码,可自定义

private static final String ENCODED_PASSWORD = "ouyangjun";

/**

* 编码

* @param str

* @return

*/

public static String encoded(String str) {

return strToHex(encodedString(str, ENCODED_PASSWORD));

}

/**

* 转换

* @param str

* @param password

* @return

*/

private static String encodedString(String str, String password) {

char[] pwd = password.toCharArray();

int pwdLen = pwd.length;

char[] strArray = str.toCharArray();

for (int i=0; i

strArray[i] = (char)(strArray[i] ^ pwd[i%pwdLen] ^ pwdLen);

}

return new String(strArray);

}

private static String strToHex(String s) {

return bytesToHexStr(s.getBytes());

}

private static String bytesToHexStr(byte[] bytesArray) {

StringBuilder builder = new StringBuilder();

String hexStr;

for (byte bt : bytesArray) {

hexStr = Integer.toHexString(bt & 0xFF);

if (hexStr.length() == 1) {

builder.append("0");

builder.append(hexStr);

}else{

builder.append(hexStr);

}

}

return builder.toString();

}

/**

* 解码

* @param str

* @return

*/

public static String decoded(String str) {

String hexStr = null;

try {

hexStr = hexStrToStr(str);

} catch (Exception e) {

e.printStackTrace();

}

if (hexStr != null) {

hexStr = encodedString(hexStr, ENCODED_PASSWORD);

}

return hexStr;

}

private static String hexStrToStr(String hexStr) {

return new String(hexStrToBytes(hexStr));

}

private static byte[] hexStrToBytes(String hexStr) {

String hex;

int val;

byte[] btHexStr = new byte[hexStr.length()/2];

for (int i=0; i

hex = hexStr.substring(2*i, 2*i+2);

val = Integer.valueOf(hex, 16);

btHexStr[i] = (byte) val;

}

return btHexStr;

}

}

二)token生成和校验工具类(包含main方法测试)

package com.oysept.token.utils;

import java.util.HashMap;

import java.util.Map;

import java.util.Map.Entry;

/**

* token生成和校验

* @author ouyangjun

*/

public class TokenUtils {

private static Map MAP_TOKENS = new HashMap();

private static final int VALID_TIME = 60*60*2; // token有效期(秒)

public static final String TOKEN_ERROR = "F"; // 非法

public static final String TOKEN_OVERDUE = "G"; // 过期

public static final String TOKEN_FAILURE = "S"; // 失效

/**

* 生成token,该token长度不一致,如需一致,可自行MD5或者其它方式加密一下

* 该方式的token只存在磁盘上,如果项目是分布式,最好用redis存储

* @param str: 该字符串可自定义,在校验token时要保持一致

* @return

*/

public static String getToken(String str) {

String token = TokenEncryptUtils.encoded(getCurrentTime()+","+str);

MAP_TOKENS.put(str, token);

return token;

}

/**

* 校验token的有效性

* @param token

* @return

*/

public static String checkToken(String token) {

if (token == null) {

return TOKEN_ERROR;

}

try{

String[] tArr = TokenEncryptUtils.decoded(token).split(",");

if (tArr.length != 2) {

return TOKEN_ERROR;

}

// token生成时间戳

int tokenTime = Integer.parseInt(tArr[0]);

// 当前时间戳

int currentTime = getCurrentTime();

if (currentTime-tokenTime < VALID_TIME) {

String tokenStr = tArr[1];

String mToken = MAP_TOKENS.get(tokenStr);

if (mToken == null) {

return TOKEN_OVERDUE;

} else if(!mToken.equals(token)) {

return TOKEN_FAILURE;

}

return tokenStr;

} else {

return TOKEN_OVERDUE;

}

}catch (Exception e) {

e.printStackTrace();

}

return TOKEN_ERROR;

}

/**获取当前时间戳(10位整数)*/

public static int getCurrentTime() {

return (int)(System.currentTimeMillis()/1000);

}

/**

* 移除过期的token

*/

public static void removeInvalidToken() {

int currentTime = getCurrentTime();

for (Entry entry : MAP_TOKENS.entrySet()) {

String[] tArr = TokenEncryptUtils.decoded(entry.getValue()).split(",");

int tokenTime = Integer.parseInt(tArr[0]);

if(currentTime-tokenTime > VALID_TIME){

MAP_TOKENS.remove(entry.getKey());

}

}

}

/**

* 测试

* @param args

*/

public static void main(String[] args) {

String str = "username_and_password";

// 获取token

String token = TokenUtils.getToken(str);

System.out.println("token Result: " + token);

// 校验token

String checkToken = TokenUtils.checkToken(token);

System.out.println("checkToken Result: " + checkToken);

if(str.equals(checkToken)) {

System.out.println("==>token verification succeeded!");

}

}

}

补充知识:JAVA后端生成Token(令牌),用于校验客户端,防止重复提交

1.概述:在web项目中,服务端和前端经常需要交互数据,有的时候由于网络相应慢,客户端在提交某些敏感数据(比如按照正常的业务逻辑,此份数据只能保存一份)时,如果前端多次点击提交按钮会导致提交多份数据,这种情况我们是要防止发生的。

2.解决方法:

①前端处理:在提交之后通过js立即将按钮隐藏或者置为不可用。

②后端处理:对于每次提交到后台的数据必须校验,也就是通过前端携带的令牌(一串唯一字符串)与后端校验来判断当前数据是否有效。

3.总结:第一种方法相对来说比较简单,但是安全系数不高,第二种方法从根本上解决了问题,所以我推荐第二种方法。

4.核心代码:

生成Token的工具类:

/**

* 生成Token的工具类:

*/

package red.hearing.eval.modules.token;

import java.security.MessageDigest;

import java.security.NoSuchAlgorithmException;

import java.util.Random;

import sun.misc.BASE64Encoder;

/**

* 生成Token的工具类

* @author zhous

* @since 2018-2-23 13:59:27

*

*/

public class TokenProccessor {

private TokenProccessor(){};

private static final TokenProccessor instance = new TokenProccessor();

public static TokenProccessor getInstance() {

return instance;

}

/**

* 生成Token

* @return

*/

public String makeToken() {

String token = (System.currentTimeMillis() + new Random().nextInt(999999999)) + "";

try {

MessageDigest md = MessageDigest.getInstance("md5");

byte md5[] = md.digest(token.getBytes());

BASE64Encoder encoder = new BASE64Encoder();

return encoder.encode(md5);

} catch (NoSuchAlgorithmException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

return null;

}

}

Token通用工具类:

/**

*

*/

package red.hearing.eval.modules.token;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;

/**

* Token的工具类

* @author zhous

* @since 2018-2-23 14:01:41

*

*/

public class TokenTools {

/**

* 生成token放入session

* @param request

* @param tokenServerkey

*/

public static void createToken(HttpServletRequest request,String tokenServerkey){

String token = TokenProccessor.getInstance().makeToken();

request.getSession().setAttribute(tokenServerkey, token);

}

/**

* 移除token

* @param request

* @param tokenServerkey

*/

public static void removeToken(HttpServletRequest request,String tokenServerkey){

request.getSession().removeAttribute(tokenServerkey);

}

/**

* 判断请求参数中的token是否和session中一致

* @param request

* @param tokenClientkey

* @param tokenServerkey

* @return

*/

public static boolean judgeTokenIsEqual(HttpServletRequest request,String tokenClientkey,String tokenServerkey){

String token_client = request.getParameter(tokenClientkey);

if(StringUtils.isEmpty(token_client)){

return false;

}

String token_server = (String) request.getSession().getAttribute(tokenServerkey);

if(StringUtils.isEmpty(token_server)){

return false;

}

if(!token_server.equals(token_client)){

return false;

}

return true;

}

}

使用方法:

①在输出前端页面的时候调用TokenTools.createToken方法,会把本次生成的token放入session中。

②然后在前端页面提交数据时从session中获取token,然后添加到要提交的数据中。

③服务端接受数据后调用judgeTokenIsEqual方法判断两个token是否一致,如果不一致则返回,不进行处理。

备注:tokenClientkey和tokenServerkey自定义,调用judgeTokenIsEqual方法时的tokenClientkey一定要与前端页面的key一致。

以上这篇java token生成和校验的实例代码就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持脚本之家。

java 生成token代码_java token生成和校验的实例代码相关推荐

  1. java 判断图片格式_Java判断上传图片格式的实例代码

    先给大家介绍下java判断上传图片格式. 由于客户上传图片将png的图片的后缀名改为jpg,所以通过后缀名判断不行,用下面这个方法可以 //判断是否是JPG格式 log.info("-1-- ...

  2. java打地鼠文本代码_Java编程实现打地鼠文字游戏实例代码

    Java编程实现打地鼠文字游戏实例代码 发布时间:2020-10-05 07:00:48 来源:脚本之家 阅读:91 作者:lao_huang123 控制台输入数字,与随机数匹配,匹配正确则返回&qu ...

  3. java计算器简单源代码_java 简单的计算器程序实例代码

    java 简单的计算器程序 实现实例: import java.awt.*; import java.awt.event.*; import javax.swing.*; public class C ...

  4. java实现人民币数字转换中文大写的工具实例代码demo分享

    原文:java实现人民币数字转换中文大写的工具实例代码demo分享 http://www.zuidaima.com/share/1816208858221568.htm 刚好在项目里面用到了数字转化为 ...

  5. java token生成和验证_Java Token登录验证 生成解析Token

    借鉴参考 Java Token登录验证 使用jjwt生成和解析JWT java基于token验证之登陆验证 等 什么是Token? 我的理解来说 token就是你访问服务器的口令,只要token合法, ...

  6. java 调用word插件_java一键生成word操作,比poi简单

    [Java] 纯文本查看 复制代码package com.jeeplus.modules.fact.util; import java.io.BufferedInputStream; import j ...

  7. java随机生成一个号码_Java 随机生成任意组电话号码过程解析

    需求说明 要求根据用户输入,生成相应组数的电话号码 实现思路 1.通过百度,获取对应真实世界中电话号码的头三位数 2.采用Math.random()方法,生成电话号码的后八位数 代码内容 随机生成任意 ...

  8. java判断三位数的范围代码_java判断三位数的实例讲解

    java判断三位数的实例讲解 java怎么判断三位数 先定义个测试数字,如图 然后可以把数字转换成字符串来判断它的长度是否为3,如图 获取判断数字范围是否在100到1000之间的值,如图 在或者判断数 ...

  9. java高效代码_Java工程师该如何编写高效代码?

    在调试 JS 代码时,很多人倾向于使用 alert() 或者 console.log() 方法来输出信息,正如某些 Java 程序员喜欢在调试代码时使用System.out.println() 输出信 ...

最新文章

  1. 前端跨域问题的解决方案
  2. Sql Server实用操作-存储过程精解
  3. jquery中的serializeArray方法的使用
  4. C#在Linux上的开发指南
  5. c++中求解非线性方程组_齐次线性方程组的基础解系的简便算法
  6. guassdb200 single node deployment
  7. spring boot几个初始配置文件
  8. egg extend ts_电竞5.21日王者荣耀KPL分析:DYG冲击西部榜首,TS战队能否虐菜?
  9. python 语音识别接口_python实现阿里云语音识别api
  10. C# 根据文本设置combobox的两种方法
  11. 【图像处理】MATLAB:频域处理
  12. 遗留非springboot传统项目接入eureka注册与服务发现
  13. bzoj3625:[Codeforces Round #250]小朋友和二叉树
  14. plex android tv版,PLEX,目前最佳的IPTV直播软件,没有之一
  15. 网线水晶头接法详细图文教程
  16. 【Java 8 新特性】Java Stream 通过min()和max()获取列表最小值和最大值
  17. vue中 this.$set的使用
  18. 在数据库中存储IP地址
  19. foxmail发邮件时总提示接收密码错误是怎么回事
  20. 测试对比了 6 款 Mac 系统监控软件,你觉得哪个最优秀?

热门文章

  1. Java Swing专栏订阅须知《必读》
  2. 基于javaweb(springboot+mybatis)网上酒类商城项目设计和实现以及文档报告
  3. linux将mysql导出表数据导入另一台服务器_远程linux服务器mysql数据库导入和导出.sql文件...
  4. mysql并发 node_nodejs写入mysql单次数据量过大的解决方法_沃航科技
  5. 没有bug队——加贝——Python 49,50
  6. 分组后统计总数_大数据时代看排球:排球技术统计能告诉你什么?
  7. 思科虚拟机配置dhpc服务器,思科模拟器配置DHCP
  8. 计算机学硕专业课可以自学吗,考研专业课怎么考?高效复习法三条就够!
  9. 面向航空航天工业领域的基于模型的仿真验证工具SkyEye
  10. vs winform常用函数_使用.net core3.0 正式版创建Winform程序