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 条评论
登录 后参与评论

相关文章

来自专栏Rgc

使用line_profiler查看api接口函数每行代码执行时间

项目情景描述:   在restful架构风格的项目交付测试的过程中,某接口出现 请求超时导致的http 502 Bad Gateway,于是开始排查具体是接口函...

3174
来自专栏区块链源码分析

以太坊源码分析之随心笔记

table.go 定期随机选取一些节点找他们要他们的节点,放到本地,也就是一个随机找节点的table 里头的bucket 和 nodesByDistan...

983
来自专栏有趣的django

面试题目及答案

1 Python的函数参数传递 看两个例子: a = 1 def fun(a): a = 2 fun(a) print a # 1 a = [] de...

6569
来自专栏算法修养

Pat 1052 Linked List Sorting (25)

1052. Linked List Sorting (25) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000...

2546
来自专栏Android群英传

Retrofit源码分析

954
来自专栏JMCui

再学习之MyBatis.

一、框架基本介绍 1、概念 支持普通SQL查询、存储过程和高级映射,简化和实现了Java 数据持久化层的的开源框架,主要流行的原因在于他的简单性和易使用性。 2...

3718
来自专栏JetpropelledSnake

Linux学习笔记之Redis中5种数据结构的使用场景介绍

原来看过 redisbook 这本书,对 redis 的基本功能都已经熟悉了,从上周开始看 redis 的源码。目前目标是吃透 redis 的数据结构。我们都知...

811
来自专栏Samego开发资源

数据库Dao层抽象出BasicDao类 | 许久没碰Java了、致Java初学者

1494
来自专栏lgp20151222

Hibernate的条件查询的几种方式

472
来自专栏Java学习网

深入了解Java对象序列化

序列化字面上指的是安排在一个序列。它是一个过程Java在对象的状态转换为比特流。转换维护一个序列按照提供的元数据,比如一个POJO。也许,这是由于这种转变从抽象...

2298

扫描关注云+社区