Token验证实现-JAVA

前言:上一篇JWT-TOKEN博客有详细介绍JWT TOKEN的原理机制,这篇博文主要是具体实现。


Token主要是用于以作客户端进行请求的一个令牌,当第一次登录后,服务器生成一个Token便将此Token返回给客户端,以后客户端只需带上这个Token前来请求数据即可,无需再次带上密匙。

1、Token工具类

package com.franz.websocket;

import com.franz.common.utils.StringUtils;
import com.franz.weixin.p3.oauth2.util.MD5Util;
import io.jsonwebtoken.*;
import net.sf.json.JSONObject;
import org.apache.commons.codec.binary.Base64;
import org.jeecgframework.core.common.service.CommonService;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import javax.xml.bind.DatatypeConverter;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;


/**
 * OAuthTokenUtils
 * Token管理
 * @author nizhigengvip@163.com
 * @version 2017-08-01
 */
public class OAuthTokenManager {
    private String APP_ID = "";
    private String APP_SECRET = "";
    private String KEY_SING =  ""; //用於存放TOKEN的標誌,Redis
    private LinkedHashMap<String, Object> pairs = new LinkedHashMap();//封装json的map
    private CommonService service;
    public static final int MINUTE_TTL = 60*1000;  //millisecond
    public static final int HOURS_TTL = 60*60*1000;  //millisecond
    public static final int DAY_TTL = 12*60*60*1000;  //millisecond



    private OAuthTokenManager() {}
    private static OAuthTokenManager single=null;
    public static OAuthTokenManager getInstance() {
            if (single == null) {
                single = new OAuthTokenManager();
            }
            return single;
        }

    public String getKEY_SING() {
        return KEY_SING;
    }

    public void setPairs(LinkedHashMap<String, Object> pairs) {
        this.pairs = pairs;
    }
    public LinkedHashMap<String, Object> getPairs() {
        return pairs;
    }

    public void put(String key, Object value){//向json中添加属性,在js中访问,请调用data.map.key
        pairs.put(key, value);
    }

    public void remove(String key){
        pairs.remove(key);
    }

    /**
     * 總體封裝
     * @param appid
     * @param secret
     * @param logicInterface 回調函數
     * @return
     */
    public String token(String appid,String secret,LogicInterface logicInterface){
        //获取appid和secret
        this.accessPairs(appid,secret);
        //验证appid和secretS,获取对象载体
        Object subject = this.loginAuthentication(logicInterface);
        //生成JWT签名数据ToKen
        String token = this.createToken(this.generalSubject(subject),this.MINUTE_TTL);
        return token;
    }

    public void accessPairs(String APP_ID, String APP_SECRET) {
        this.APP_ID = APP_ID;
        this.APP_SECRET = APP_SECRET;
        //this.KEY_SING = MD5Util.MD5Encode(APP_ID+"_"+APP_SECRET, "UTF-8").toUpperCase();//要用到的时候才用
    }

    public Object loginAuthentication(LogicInterface logicInterface){
        if (StringUtils.isNotBlank(APP_ID) && StringUtils.isNotBlank(APP_SECRET)) {
                Map<String, Object> map = new HashMap<>();
                map.put("APP_ID",APP_ID);
                map.put("APP_SECRET",APP_SECRET);
                if(logicInterface == null || logicInterface.handler(map) == null){
                    return map;
                }else {
                    return logicInterface.handler(map);
                }
        } else {
            return null;
        }
    }
    /**
     * 由字符串生成加密key
     * @return
     */
    public SecretKey generalKey(){
        String stringKey = APP_ID+APP_SECRET;
        byte[] encodedKey = Base64.decodeBase64(stringKey);
        SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
        return key;
    }
    /**
     * 生成subject信息
     * @param obj
     * @return
     */
    public static String generalSubject(Object obj){
        if(obj != null ) {
            JSONObject json = JSONObject.fromObject(obj);
            return json.toString();
        }else{
            return "{}";
        }

    }

    /**
     * 创建token
     * @param subject
     * @param ttlMillis
     * @return
     * @throws Exception
     */
    public String createToken(String subject, long ttlMillis) {

        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        SecretKey key = generalKey();
        JwtBuilder builder = Jwts.builder()
                .setId(APP_ID)
                .setIssuedAt(now)
                .setSubject(subject)
                .signWith(signatureAlgorithm, key);
        if (ttlMillis >= 0) {
            long expMillis = nowMillis + ttlMillis;
            Date exp = new Date(expMillis);
            builder.setExpiration(exp);
        }
        return builder.compact();
    }

    /**
     * 解密token
     * @param token
     * @return
     * @throws Exception
     */
    public Claims validateToken(String token) throws Exception{
        Claims claims = Jwts.parser()
                .setSigningKey(generalKey())
                .parseClaimsJws(token).getBody();
        /*System.out.println("ID: " + claims.getId());
        System.out.println("Subject: " + claims.getSubject());
        System.out.println("Issuer: " + claims.getIssuer());
        System.out.println("Expiration: " + claims.getExpiration());*/
        return claims;
    }



}

2、业务逻辑接口

public interface LogicInterface { //其实这个接口,主要用于回调函数,如果不考虑用也可以
    /**
     * 處理業務
     * @param map
     */
    public Map<String, Object> handler(Map<String, Object> map);
}


3、ControllerWeb
import com.ewider.weixin.p3.oauth2.util.MD5Util;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureException;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * OAuthTokenController
 *
 * @author Franz.ge.倪志耿
 * @version 2017-08-01
 */
@Scope("prototype")
@Controller
@RequestMapping("/oAuthToken")
public class OAuthToken {

    /**
     * 獲取Token
     * @param grant_type
     * @param appid
     * @param secret
     * @return
     */
    @RequestMapping(params = "token",method = RequestMethod.GET)
    @ResponseBody
    public Object token (@RequestParam(value = "grant_type") String grant_type, @RequestParam(value = "appid") String appid,
            @RequestParam(value = "secret") String secret,HttpServletResponse response) {
        Map<String, Object> map = new HashMap<>();
        switch (grant_type) {
            case "authorization_code" : //授权码模式(即先登录获取code,再获取token)
                break;
            case "password" : //密码模式(将用户名,密码传过去,直接获取token)
                break;
            case "client_credentials" : //客户端模式(无用户,用户向客户端注册,然后客户端以自己的名义向’服务端’获取资源)
                OAuthTokenManager oAuthTokenManager = OAuthTokenManager.getInstance();
                String token = oAuthTokenManager.token(appid, secret,null);//loginInterface是业务逻辑回掉函数
                //返回Token
                map.put("access_token",token);
                map.put("expires_in",OAuthTokenManager.MINUTE_TTL/1000);
                break;
            case "implicit" : //简化模式(在redirect_uri 的Hash传递token; Auth客户端运行在浏览器中,如JS,Flash)
                break;
            case "refresh_token" : //刷新access_token
                break;
        }

        return map;
    }

    @RequestMapping(params = "loginAuth2",method = RequestMethod.GET)
    @ResponseBody
    public Object loginAuth2 (HttpServletRequest request, HttpServletResponse response, @RequestParam(value = "accessToken") String accessToken ){
        Map<String, Object> map = new HashMap<>();
        //COOKIE不存在:解析验证正确性
        try {
                OAuthTokenManager oAuthTokenManager = OAuthTokenManager.getInstance();
                Claims claims = oAuthTokenManager.validateToken(accessToken);
                if (claims != null ) {
                    map.put("state","success");
                    map.put("loginAuth","采用Token登录");
                    int validMillis = (int)(claims.getExpiration().getTime()-System.currentTimeMillis());
                    if(validMillis > 0) {
                        //交給容器管理,可以存放redis,這裡模擬是cookie
                        Cookie cookie = new Cookie(MD5Util.MD5Encode("MD5SING", "UTF-8").toUpperCase(), accessToken);
                        cookie.setMaxAge(validMillis/1000);
                        response.addCookie(cookie);
                    }

                }else{
                    map.put("state","fail");
                }
            }catch (MalformedJwtException | SignatureException e){
                     map.put("state","signature");//改造簽名,或者無效的Token
                     map.put("loginAuth","該Token無效");//改造簽名,或者無效的Token
            }catch (ExpiredJwtException e){
                     map.put("state","expired");//改造簽名,或者無效的Token
                     map.put("loginAuth","Token已經過時");
            }catch (Exception e) {
            e.printStackTrace();
            map.put("state","fail");
            }
            return map;
    }

    @RequestMapping(params = "index",method = RequestMethod.GET)
    @ResponseBody
    public Object index (HttpServletRequest request, HttpServletResponse response){
        Map<String, Object> map = new HashMap<>();
        //从COOKIE中查找,模拟访问,可以集成容器管理
        Cookie[] cookies = request.getCookies();
        if (cookies!=null) {
            for (int i = cookies.length-1; i >= 0; i--) {
                Cookie cookie = cookies[i];
                if (cookie.getName().equals(MD5Util.MD5Encode("MD5SING", "UTF-8").toUpperCase())) {
                    //跳过登陆
                    map.put("index","采用Redis登录");
                    return map;
                }
            }
        }
        map.put("index","你的Token已经销毁");
        return map;
    }

}


4、加入jar包,里面有MD5.jar(这个网上博客各有实现也有jar,自行导入下载)

     重点然后加入JJWT-0.7.0.jar

<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt -->
		<dependency>
			<groupId>io.jsonwebtoken</groupId>
			<artifactId>jjwt</artifactId>
			<version>0.7.0</version>
		</dependency>

总结:如果不清楚JWT TOKEN的原理机制,我的上一篇JWT-TOKEN博客有详细介绍,这篇博文主要是具体实现。

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
Java实现Token登录验证可以通过以下步骤来实现: 1. 用户登录时,服务器端生成一个Token,并将Token与用户信息关联存储起来。Token可以是一个随机生成的字符串,也可以使用JWT(JSON Web Token)等标准方式生成。 2. 服务器将生成的Token返回给客户端,在登录接口的响应中包含Token信息。 3. 客户端在后续请求中将Token以特定的方式传递给服务器。常见的方式有将Token放在请求头的Authorization字段中,或者放在请求参数中。 4. 服务器接收到请求后,从请求中获取Token,并根据存储的Token信息进行验证验证方式可以是查询数据库或缓存中的Token信息,或者使用JWT解析Token验证签名等。 5. 如果验证成功,服务器可以根据Token关联的用户信息进行相应操作。如果验证失败,则返回相应的错误信息。 以下是一个简单的示例代码: ```java // 生成Token并关联用户信息 public String generateToken(User user) { // 生成随机字符串作为Token String token = generateRandomString(); // 将Token与用户信息关联存储起来,例如存储在数据库或缓存中 tokenRepository.saveToken(token, user); return token; } // 验证Token public boolean validateToken(String token) { // 查询数据库或缓存中的Token信息 TokenInfo tokenInfo = tokenRepository.getTokenInfo(token); if (tokenInfo != null && tokenInfo.isValid()) { // Token验证通过 return true; } else { // Token验证失败 return false; } } // 示例的登录接口 public ResponseEntity<?> login(String username, String password) { // 根据用户名和密码验证用户身份 User user = userRepository.getUserByUsernameAndPassword(username, password); if (user != null) { // 登录成功,生成Token并返回给客户端 String token = generateToken(user); // 将Token放入响应的头部或作为响应体返回给客户端 HttpHeaders headers = new HttpHeaders(); headers.add("Authorization", "Bearer " + token); return ResponseEntity.ok().headers(headers).build(); } else { // 登录失败 return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); } } ``` 请注意,这只是一个简单示例,并未涵盖所有细节。在实际开发中,您可能需要更加完善的实现,并考虑安全性、Token的过期时间、刷新Token等方面的问题。同时也可以结合框架或库来简化Token验证的过程。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值