JAVA中的Token 基于Token的身份验证实例

网友投稿 442 2022-11-25


JAVA中的Token 基于Token的身份验证实例

最近在做项目开始,涉及到服务器与安卓之间的接口开发,在此开发过程中发现了安卓与一般浏览器不同,安卓在每次发送请求的时候并不会带上上一次请求的SessionId,导致服务器每次接收安卓发送的请求访问时都新建一个Session进行处理,无法通过传统的绑定Session来进行保持登录状态和通讯状态。

基于传统方法无法判断安卓的每次请求访问状态,故查询资料了解到Token,特殊的身份证验证。以下是网上搜寻资料所得,作为学习总结资料。

令牌是一种能够控制站点占有媒体的特殊帧,以区别数据帧及其他控制帧。token其实说的更通俗点可以叫暗号,在一些数据传输之前,要先进行暗号的核对,不同的暗号被授权不同的数据操作,下文我们就来详细的介绍一下关于基于 Token 的身份验证的教程

最近了解下基于 Token 的身份验证,跟大伙分享下。很多大型网站也都在用,比如 Facebook,Twitter,Google+,github 等等,比起传统的身份验证方法,Token 扩展性更强,也更安全点,非常适合用在 Web 应用或者移动应用上。Token 的中文有人翻译成 “令牌”,我觉得挺好,意思就是,你拿着这个令牌,才能过一些关卡。

传统身份验证的方法

HTTP 是一种没有状态的协议,也就是它并不知道是谁是访问应用。这里我们把用户看成是客户端,客户端使用用户名还有密码通过了身份验证,不过下回这个客户端再发送请求时候,还得再验证一下。

解决的方法就是,当用户请求登录的时候,如果没有问题,我们在服务端生成一条记录,这个记录里可以说明一下登录的用户是谁,然后把这条记录的 ID 号发送给客户端,客户端收到以后把这个 ID 号存储在 Cookie 里,下次这个用户再向服务端发送请求的时候,可以带着这个 Cookie ,这样服务端会验证一个这个 Cookie 里的信息,看看能不能在服务端这里找到对应的记录,如果可以,说明用户已经通过了身份验证,就把用户请求的数据返回给客户端。Cookie里面存的是sessionID是session记录的id.

上面说的就是 Session,我们需要在服务端存储为登录的用户生成的 Session ,这些 Session 可能会存储在内存,磁盘,或者数据库里。我们可能需要在服务端定期的去清理过期的 Session 。

基于 Token 的身份验证方法

使用基于 Token 的身份验证方法,在服务端不需要存储用户的登录记录。大概的流程是这样的:

客户端使用用户名跟密码请求登录

服务端收到请求,去验证用户名与密码

验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端

客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里或者 Local Storage 里

客户端每次向服务端请求资源的时候需要带着服务端签发的 Token

服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据

JWT

实施 Token 验证的方法挺多的,还有一些标准方法,比如 JWT,读作:jot ,表示:jsON Web Tokens 。JWT 标准的 Token 有三个部分:

header

payload

signature

中间用点分隔开,并且都会使用 Base64 编码,所以真正的 Token 看起来像这样:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJuaW5naGFvLm5ldCIsImV4cCI6IjE0Mzg5NTU0NDUiLCJuYW1lIjoid2FuZ2hhbyIsImFkbWluIjp0cnVlfQ.SwyHTEx_RQppr97g4J5lKXtabJecpejuef8AqKYMAJc

Header

header 部分主要是两部分内容,一个是 Token 的类型,另一个是使用的算法,比如下面类型就是 JWT,使用的算法是 HS256。

{

"typ": "JWT",

"alg": "HS256"

}

上面的内容要用 Base64 的形式编码一下,所以就变成这样:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

Payload

Payload 里面是 Token 的具体内容,这些内容里面有一些是标准字段,你也可以添加其它需要的内容。

下面是标准字段:

iss:Issuer,发行者 sub:Subject,主题 aud:Audience,观众 exp:Expiration time,过期时间 nbf:Not before iat:Issued at,发行时间 jti:JWT ID

比如下面这个 Payload ,用到了 iss 发行人,还有 exp 过期时间。另外还有两个自定义的字段,一个是 name ,还有一个是 admin 。

{

"iss": "ninghao.net",

"exp": "1438955445",

"name": "wanghao",

"admin": true

}

使用 Base64 编码以后就变成了这个样子:

eyJpc3MiOiJuaW5naGFvLm5ldCIsImV4cCI6IjE0Mzg5NTU0NDUiLCJuYW1lIjoid2FuZ2hhbyIsImFkbWluIjp0cnVlfQ

Signature

JWT 的最后一部分是 Signature ,这部分内容有三个部分,先是用 Base64 编码的 header.payload ,再用加密算法加密一下,加密的时候要放进去一个 Secret ,这个相当于是一个密码,这个密码秘密地存储在服务端。

header

payload

secret

var encodedString = base64UrlEncode(header) + "." + base64UrlEncode(payload);

HMACSHA256(encodedString, 'secret');

处理完成以后看起来像这样:

SwyHTEx_RQppr97g4J5lKXtabJecpejuef8AqKYMAJc

最后这个在服务端生成并且要发送给客户端的 Token 看起来像这样:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJuaW5naGFvLm5ldCIsImV4cCI6IjE0Mzg5NTU0NDUiLCJuYW1lIjoid2FuZ2hhbyIsImFkbWluIjp0cnVlfQ.SwyHTEx_RQppr97g4J5lKXtabJecpejuef8AqKYMAJc

客户端收到这个 Token 以后把它存储下来,下回向服务端发送请求的时候就带着这个 Token 。服务端收到这个 Token ,然后进行验证,通过以后就会返回给客户端想要的资源。

补充知识:java后端生成Token(令牌),用于校验客户端

1.概述:

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

2.解决方法:

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

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

3.总结:

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

**

* 生成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;

}

}

/**

*

*/

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(HttZKcNYSSBpServletRequest 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;

}

}


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

上一篇:java定义受限制的类型参数操作
下一篇:利用JAVA反射,读取数据库表名,自动生成对应实体类的操作
相关文章

 发表评论

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