app令牌的一个token实现

app登陆验证不能使用session来判断了。然后查资料都说用令牌,没找到合适的方法,我的眼界太小。另外,越来越感觉基础的重要,比如,session是什么,我竟无言以对。不知道session是什么,怎么来做验证呢。然后就关于类的加载和销毁,等。我需要重新看下java基础了。

这里,我定义了一个token类来存储token。就是一个字符串+创建的时间戳。然后定义一个管理类来维护token。简单的实现了,但还有很多问题。比如,我对session的理解(是否可以放session,放session之后什么状态),比如这定义的这个类在调用的时候加载,在不用的时间结束,而我希望一直存在,这个维护类怎么确保存在,这是类的声明周期问题,比如加载到内存和缓存的实现,缓存用的太少。

1.Token.java

 1 package com.tixa.wedding.util;
 2 
 3 import java.io.Serializable;
 4 
 5 public class Token implements Serializable {
 6     
 7     /** 
 8     * @Fields serialVersionUID : TODO
 9     */ 
10     private static final long serialVersionUID = -754659525548951914L;
11     private String signature;
12     private long timestamp;
13     
14     public Token(String signature, long timestamp) {
15         if (signature == null)
16             throw new IllegalArgumentException("signature can not be null");
17         
18         this.timestamp = timestamp;
19         this.signature = signature;
20     }
21     
22     public Token(String signature) {
23         if (signature == null)
24             throw new IllegalArgumentException("signature can not be null");
25         
26         this.signature = signature;
27     }
28     
29     /**
30      * Returns a string containing the unique signatureentifier assigned to this token.
31      */
32     public String getSignature() {
33         return signature;
34     }
35     
36     public long getTimestamp() {
37         return timestamp;
38     }
39     
40     /**
41      * timestamp 不予考虑, 因为就算 timestamp 不同也认为是相同的 token.
42      */
43     public int hashCode() {
44         return signature.hashCode();
45     }
46     
47     public boolean equals(Object object) {
48         if (object instanceof Token)
49             return ((Token)object).signature.equals(this.signature);
50         return false;
51     }
52 
53     @Override
54     public String toString() {
55         return "Token [signature=" + signature + ", timestamp=" + timestamp
56                 + "]";
57     }
58     
59     
60 }

2.TokenUtil.java

  1 package com.tixa.wedding.util;
  2 
  3 import java.security.MessageDigest;
  4 import java.util.Calendar;
  5 import java.util.Date;
  6 import java.util.HashMap;
  7 import java.util.Map;
  8 import java.util.Map.Entry;
  9 import java.util.concurrent.Executors;
 10 import java.util.concurrent.ScheduledExecutorService;
 11 import java.util.concurrent.TimeUnit;
 12 
 13 import org.apache.log4j.Logger;
 14 
 15 
 16 
 17 public class TokenUtil {
 18 
 19     private static final int INTERVAL = 7;// token过期时间间隔 天
 20     private static final String YAN = "testMRf1$789787aadfjkds//*-+'[]jfeu;384785*^*&%^%$%";// 加盐
 21     private static final int HOUR = 3;// 检查token过期线程执行时间 时
 22     
 23     private static Logger logger = Logger.getLogger("visit");
 24 
 25     private static Map<Integer, Token> tokenMap = new HashMap<Integer, Token>();
 26     private static TokenUtil tokenUtil = null;
 27     static ScheduledExecutorService scheduler =Executors.newSingleThreadScheduledExecutor(); 
 28 
 29     static {
 30         logger.info("\n===============进入TokenUtil静态代码块==================");
 31         listenTask();
 32     }
 33     
 34 
 35     public static TokenUtil getTokenUtil() {
 36         if (tokenUtil == null) {
 37             synInit();
 38         }
 39 
 40         return tokenUtil;
 41     }
 42 
 43     private static synchronized void synInit() {
 44         if (tokenUtil == null) {
 45             tokenUtil = new TokenUtil();
 46         }
 47     }
 48 
 49     public TokenUtil() {
 50     }
 51     
 52     
 53 
 54     public static Map<Integer, Token> getTokenMap() {
 55         return tokenMap;
 56     }
 57 
 58     /**
 59      * 产生一个token
 60      */
 61     public static Token generateToken(String uniq,int id) {
 62         Token token = new Token(MD5(System.currentTimeMillis()+YAN+uniq+id), System.currentTimeMillis());
 63         synchronized (tokenMap) {
 64             tokenMap.put(id, token);
 65         }
 66         return token;
 67     }
 68 
 69 
 70     /**
 71      * @Title: removeToken
 72      * @Description: 去除token
 73      * @param @param nonce
 74      * @param @return 参数
 75      * @return boolean 返回类型
 76      */
 77     public static boolean removeToken(int id) {
 78         synchronized (tokenMap) {
 79             tokenMap.remove(id);
 80             logger.info(tokenMap.get(id) == null ? "\n=========已注销========": "\n++++++++注销失败+++++++++++++++");
 81         }
 82         return true;
 83     }
 84 
 85     /**
 86      * @Title: volidateToken
 87      * @Description: 校验token
 88      * @param @param signature
 89      * @param @param nonce
 90      * @param @return 参数
 91      * @return boolean 返回类型
 92      */
 93     public static boolean volidateToken(String signature, int id) {
 94         boolean flag = false;
 95         Token token = (Token) tokenMap.get(id);
 96         if (token != null && token.getSignature().equals(signature)) {
 97             logger.info("\n=====已在线=======");
 98             flag = true;
 99         }
100 
101         return flag;
102     }
103     
104     /**
105      * 
106      * @Title: MD5
107      * @Description: 加密
108      * @param @param s
109      * @param @return 参数
110      * @return String 返回类型
111      */
112     public final static String MD5(String s) {
113         try {
114             byte[] btInput = s.getBytes();
115             // 获得MD5摘要算法的 MessageDigest 对象
116             MessageDigest mdInst = MessageDigest.getInstance("MD5");
117             // 使用指定的字节更新摘要
118             mdInst.update(btInput);
119             // 获得密文
120             return byte2hex(mdInst.digest());
121         } catch (Exception e) {
122             e.printStackTrace();
123             return null;
124         }
125     }
126 
127     /**
128      * 将字节数组转换成16进制字符串
129      * @param b
130      * @return
131      */
132     private static String byte2hex(byte[] b) {
133         StringBuilder sbDes = new StringBuilder();
134         String tmp = null;
135         for (int i = 0; i < b.length; i++) {
136             tmp = (Integer.toHexString(b[i] & 0xFF));
137             if (tmp.length() == 1) {
138                 sbDes.append("0");
139             }
140             sbDes.append(tmp);
141         }
142         return sbDes.toString();
143     }
144     
145     /**
146     * @Title: listenTask 
147     * @Description: 定时执行token过期清除任务
148     * @param     参数
149     * @return void    返回类型
150      */
151     public static void listenTask(){
152         Calendar calendar = Calendar.getInstance();
153         int year = calendar.get(Calendar.YEAR);
154         int month = calendar.get(Calendar.MONTH);
155         int day = calendar.get(Calendar.DAY_OF_MONTH);
156         //定制每天的HOUR点,从明天开始
157         calendar.set(year, month, day+1, HOUR, 0, 0);
158        // calendar.set(year, month, day, 17, 11, 40);
159         Date date = calendar.getTime();
160         
161         scheduler.scheduleAtFixedRate( new ListenToken(), (date.getTime()-System.currentTimeMillis())/1000, 60*60*24, TimeUnit.SECONDS);
162     }
163     
164     
165 
166     /**
167      * @ClassName: ListenToken
168      * @Description: 监听token过期线程runnable实现
169      * @author mrf
170      * @date 2015-10-21 下午02:22:24
171      * 
172      */
173     static class ListenToken implements Runnable {
174         public ListenToken() {
175             super();
176         }
177 
178         public void run() {
179             logger.info("\n**************************执行监听token列表****************************");
180             try {
181                 synchronized (tokenMap) {
182                     for (int i = 0; i < 5; i++) {
183                         if (tokenMap != null && !tokenMap.isEmpty()) {
184                             for (Entry<Integer, Token> entry : tokenMap.entrySet()) {
185                                 Token token = (Token) entry.getValue();
186                                 logger.info("\n==============已登录用户有:"+entry + "=====================");
187 //                            try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}
188                                 int interval = (int) ((System.currentTimeMillis() - token.getTimestamp()) / 1000 / 60 / 60 / 24);
189                                 if (interval > INTERVAL) {
190                                     tokenMap.remove(entry.getKey());
191                                     logger.info("\n==============移除token:" + entry+ "=====================");
192                                 }
193 
194                             }
195                         }
196                     }
197                     
198                 }
199             } catch (Exception e) {
200                 logger.error("token监听线程错误:"+e.getMessage());
201                 e.printStackTrace();
202             }
203         }
204     }
205     
206      
207 
208     public static void main(String[] args) {
209         System.out.println(generateToken( "s",1));
210         System.out.println(generateToken( "q",1));
211         System.out.println(generateToken( "s3",2));
212         System.out.println(generateToken( "s4",3));
213         System.out.println(removeToken(3));
214         System.out.println(getTokenMap());
215     }
216 
217 }
218 
219  

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏coolblog.xyz技术专栏

基于 Java NIO 实现简单的 HTTP 服务器

本文是上一篇文章实践篇,在上一篇文章中,我分析了选择器 Selector 的原理。本篇文章,我们来说说 Selector 的应用,如标题所示,这里我基于 Jav...

59212
来自专栏微服务那些事儿

关键数据变更监控

在经过了对mybatis的一番检索之后,没有发现对该需求的解决方式.在认知范围内,想到了使用mabatis拦截器解决该问题。

60219
来自专栏大数据学习笔记

Hadoop源码分析:FileSystem类

1、org.apache.hadoop.conf包 org.apache.hadoop.conf包位于hadoop-common模块下 ? 1.1 Con...

3287
来自专栏Android机动车

使用Retrofit+RxJava实现带进度下载文件

Retrofit+RxJava已经是目前市场上最主流的网络框架,使用它进行平常的网络请求异常轻松,之前也用Retrofit做过上传文件和下载文件,但发现:使用R...

711
来自专栏我是攻城师

高效读取大数据文本文件(上亿行数据)

3314
来自专栏码匠的流水账

reactor-netty中HttpClient对TcpClient的封装

本文主要研究一下reactor-netty中HttpClient对TcpClien的封装

1111
来自专栏java达人

SpringBoot编写自定义的starter

作者:Format 来源:http://fangjian0423.github.io/2016/11/16/springboot-custom-starter/...

2747
来自专栏刘望舒

Android网络编程(二)HttpClient与HttpURLConnection

相关文章 Android网络编程(一)HTTP协议原理 前言 上一篇我们了解了HTTP协议原理,这一篇我们来讲讲Apache的HttpClient和Java的...

1837
来自专栏Java后端技术

Spring+SpringMvc+Mybatis框架集成搭建教程三(框架整合测试程序开发)

(2).在main文件夹下的java源文件夹下创建com.hafiz.www包,并在该包下依次创建:

593
来自专栏yukong的小专栏

【SpringBoot2.0系列07】SpringBoot之redis使用(Lettuce版本)

【SpringBoot2.0系列02】SpringBoot之使用Thymeleaf视图模板

2052

扫码关注云+社区