java token生成和校验的实例代码

网友投稿 419 2022-11-22


java token生成和校验的实例代码

现在越来越多的登录方式都用到了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项目中,服务端和前端经常需要交互数据,有的时候由于网络http://相应慢,客户端在提交某些敏感数据(比如按照正常的业务逻辑,此份数据只能保存一份)时,如果前端多次点击提交按钮会导致提交多份数据,这种情况我们是要防止发生的。

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一致。

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

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一致。

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

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一致。


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

上一篇:SpringBoot启动过程的实现
下一篇:SpringBoot Security前后端分离登录验证的实现
相关文章

 发表评论

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