为什么要告别session?有这样一个场景,系统的数据量达到千万级,需要几台服务器部署,当一个用户在其中一台服务器登录后,用session保存其登录信息,其他服务器怎么知道该用户登录了?(单点登录),当然解决办法有,可以用spring-session。如果该系统同时为移动端服务呢?移动端通过url向后台要数据,如果用session,通过sessionId识别用户,万一sessionId被截获了,别人可以利用sessionId向后台要数据,就有安全隐患了。所以有必要跟session说拜拜了。服务端不需要存储任何用户的信息,用户的验证应该放在客户端,jwt就是这种方式!

什么是jwt?

最详细的是官网:https://jwt.io/

这里以java的ssm框架为例,集成jwt。

1.pom.xml 导入jwt的包

 
 
 
 
 
 
 <!-- jwt -->
   <!-- https://mvnrepository.com/artifact/com.auth0/java-jwt -->
   <dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>2.2.0</version>
   </dependency>
 

2.编写jwt的工具类,有加密解密功能就好

 
 
 
 
 
import com.auth0.jwt.JWTSigner;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.internal.com.fasterxml.jackson.databind.ObjectMapper;
import java.util.HashMap;
import java.util.Map;
public class JWT {
    private static final String SECRET = "XX#$%()(#*!()!KL<><MQLMNQNQJQK sdfkjsdrow32234545fdf>?N<:{LWPW";
    private static final String EXP = "exp";
    private static final String PAYLOAD = "payload";
    //加密,传入一个对象和有效期
    public static <T> String sign(T object, long maxAge) {
        try {
            final JWTSigner signer = new JWTSigner(SECRET);
            final Map<String, Object> claims = new HashMap<String, Object>();
            ObjectMapper mapper = new ObjectMapper();
            String jsonString = mapper.writeValueAsString(object);
            claims.put(PAYLOAD, jsonString);
            claims.put(EXP, System.currentTimeMillis() + maxAge);
            return signer.sign(claims);
        } catch(Exception e) {
            return null;
        }
    }
    //解密,传入一个加密后的token字符串和解密后的类型
    public static<T> T unsign(String jwt, Class<T> classT) {
        final JWTVerifier verifier = new JWTVerifier(SECRET);
        try {
            final Map<String,Object> claims= verifier.verify(jwt);
            if (claims.containsKey(EXP) && claims.containsKey(PAYLOAD)) {
                long exp = (Long)claims.get(EXP);
                long currentTimeMillis = System.currentTimeMillis();
                if (exp > currentTimeMillis) {
                    String json = (String)claims.get(PAYLOAD);
                    ObjectMapper objectMapper = new ObjectMapper();
                    return objectMapper.readValue(json, classT);
                }
            }
            return null;
        } catch (Exception e) {
            return null;
        }
 
    }
}
 

3.jwt有了,ssm要如何去利用,用户验证的第一步是登录,登录时根据用户传来的username和password到数据库验证身份,如果合法,便给该用户jwt加密生成token

 
 
 
 
 
//处理登录
    @RequestMapping(value="login", produces = "application/json; charset=utf-8")
    public @ResponseBody ResponseData login(HttpServletRequest request, @RequestParam( "email") String email,
            @RequestParam("password") String password) {
        Login login = new Login();
        login.setEmail(email);
        login.setPassword(password);
        ResponseData responseData = ResponseData.ok();
        //先到数据库验证
        Integer loginId = userService.checkLogin(login);
        if(null != loginId) {
            User user = userService.getUserByLoginId(loginId);
            login.setId(loginId);
            //给用户jwt加密生成token
            String token = JWT.sign(login, 60L* 1000L* 30L);
            //封装成对象返回给客户端
            responseData.putDataValue("loginId", login.getId());
            responseData.putDataValue("token", token);
            responseData.putDataValue("user", user);
 
        }
        else{
            responseData =  ResponseData.customerError();
        }   
        return responseData;
    }
 

4.在用户登录时,把loginId和token返回给前台,以后用户每次请求时,都得带上这两个参数,后台拿到token后解密出loginId,与用户传递过来的loginId比较,如果相同,则说明用户身份合法。因为是每个登录过后的每个请求,这里用springmvc的拦截器做

 
 
 
 
 
<mvc:interceptors>    
    <mvc:interceptor>    
        <!-- 匹配的是url路径, 如果不配置或/**,将拦截所有的Controller -->  
        <mvc:mapping path="/**" />  
        <!-- /register 和 /login 不需要拦截-->  
        <mvc:exclude-mapping path="/register" />
        <mvc:exclude-mapping path="/login" />
 
        <bean class="com.xforce.charles.interceptor.TokenInterceptor"></bean>    
    </mvc:interceptor>  
    <!-- 当设置多个拦截器时,先按顺序调用preHandle方法,然后逆序调用每个拦截器的postHandle和afterCompletion方法 -->  
    </mvc:interceptors> 
 

5.拦截器代码

 
 
 
 
 
import java.io.PrintWriter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import com.alibaba.fastjson.JSONObject;
import com.xforce.charles.model.Admin;
import com.xforce.charles.model.Login;
import com.xforce.charles.util.JWT;
import com.xforce.charles.util.ResponseData;
public class TokenInterceptor implements HandlerInterceptor{
    public void afterCompletion(HttpServletRequest request,
            HttpServletResponse response, Object handler, Exception arg3)
            throws Exception {
    }
    public void postHandle(HttpServletRequest request, HttpServletResponse response,
            Object handler, ModelAndView model) throws Exception {
    }
    //拦截每个请求
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
            Object handler) throws Exception {
        response.setCharacterEncoding("utf-8");
        String token = request.getParameter("token");
        ResponseData responseData = ResponseData.ok();
        //token不存在
        if(null != token) {
            Login login = JWT.unsign(token, Login.class);
            String loginId = request.getParameter("loginId");
            //解密token后的loginId与用户传来的loginId不一致,一般都是token过期
            if(null != loginId && null != login) {
                if(Integer.parseInt(loginId) == login.getId()) {
                    return true;
                }
                else{
                    responseData = ResponseData.forbidden();
                    responseMessage(response, response.getWriter(), responseData);
                    return false;
                }
            }
            else
            {
                responseData = ResponseData.forbidden();
                responseMessage(response, response.getWriter(), responseData);
                return false;
            }
        }
        else
        {
            responseData = ResponseData.forbidden();
            responseMessage(response, response.getWriter(), responseData);
            return false;
        }
    }
    //请求不通过,返回错误信息给客户端
    private void responseMessage(HttpServletResponse response, PrintWriter out, ResponseData responseData) {
        responseData = ResponseData.forbidden();
        response.setContentType("application/json; charset=utf-8");  
        String json = JSONObject.toJSONString(responseData);
        out.print(json);
        out.flush();
        out.close();
    }
 
}
 

6.注意点:用@ResponseBody返回json数据时,有时会有乱码,需要在springmvc的配置文件里面加以下配置(spring4以上)

 
 
 
 
 
<mvc:annotation-driven>
     <mvc:message-converters register-defaults="true">
    <bean class="org.springframework.http.converter.StringHttpMessageConverter">
 
      <property name="supportedMediaTypes" value = "text/plain;charset=UTF-8" />
    </bean>
   </mvc:message-converters>
     </mvc:annotation-driven>  
 

7.最后分享一个类,用于返回给客户端的万能类,我觉得它可以满足一般的接口

 
 
 
 
 
import java.util.HashMap;
import java.util.Map;
public class ResponseData {
    private final String message;
    private final int code;
    private final Map<String, Object> data = new HashMap<String, Object>();
    public String getMessage() {
        return message;
    }
    public int getCode() {
        return code;
    }
    public Map<String, Object> getData() {
        return data;
    }
    public ResponseData putDataValue(String key, Object value) {
        data.put(key, value);
        return this;
    }
    private ResponseData(int code, String message) {
        this.code = code;
        this.message = message;
    }
    public static ResponseData ok() {
        return new ResponseData(200, "Ok");
    }
    public static ResponseData notFound() {
        return new ResponseData(404, "Not Found");
    }
    public static ResponseData badRequest() {
        return new ResponseData(400, "Bad Request");
    }
    public static ResponseData forbidden() {
        return new ResponseData(403, "Forbidden");
    }
    public static ResponseData unauthorized() {
        return new ResponseData(401, "unauthorized");
    }
    public static ResponseData serverInternalError() {
        return new ResponseData(500, "Server Internal Error");
    }
    public static ResponseData customerError() {
        return new ResponseData(1001, "customer Error");
    }
}

jwt验证登录信息的更多相关文章

  1. Jwt验证登录

    练习模板:https://gitee.com/zh1446802857/swagger-multi-version-api.git Jwt在我的 认知里,是一套门锁.别人(用户)需要用到你的接口 的时 ...

  2. 解决:使用ajax验证登录信息返回前端页面时,当前整个页面刷新。

    源代码如下: function loginform(){ $.ajax({ url:"loginValidate.do", type:'post', data:{"nam ...

  3. 从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 二十四║ Vuex + JWT 实现授权验证登录

    壹周回顾 哈喽,又是元气满满的一个周一,又与大家见面了,周末就是团圆节了,正好咱们的前后端也要团圆了,为什么这么说呢,因为以后的开发可能就需要前后端一起了,两边也终于会师了,还有几天Vue系列就基本告 ...

  4. golang学习笔记10 beego api 用jwt验证auth2 token 获取解码信息

    golang学习笔记10 beego api 用jwt验证auth2 token 获取解码信息 Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放 ...

  5. Python 解密JWT验证苹果登录

    验证苹果登录,官方提供两种验证方法,一种是token,另一个种是code.这里使用的是token 登录流程: 苹果客户端调用苹果API,获取到用户的信息,包括: user_id 昵称 identity ...

  6. spring boot:spring security整合jwt实现登录和权限验证(spring boot 2.3.3)

    一,为什么使用jwt? 1,什么是jwt? Json Web Token, 它是JSON风格的轻量级的授权和身份认证规范, 可以实现无状态.分布式的Web应用授权 2,jwt的官网: https:// ...

  7. Spring 笔记 -06- 从 MySQL 建库到 登录验证数据库信息(maven)

    Spring 笔记 -06- 从 MySQL 建库到 登录验证数据库信息(maven) 本篇和 Spring 没有什么关系,只是学习 Spring,必备一些知识,所以放在这里了. 本篇内容: (1)M ...

  8. spring集成jwt验证方式,token验证

    为什么要告别session?有这样一个场景,系统的数据量达到千万级,需要几台服务器部署,当一个用户在其中一台服务器登录后,用session保存其登录信息,其他服务器怎么知道该用户登录了?(单点登录), ...

  9. webapi中使用token验证(JWT验证)

    本文介绍如何在webapi中使用JWT验证 准备 安装JWT安装包 System.IdentityModel.Tokens.Jwt 你的前端api登录请求的方法,参考 axios.get(" ...

随机推荐

  1. 创建元素节点createElement

    <!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" content ...

  2. 【BZOJ3884】上帝与集合的正确用法(欧拉定理,数论)

    [BZOJ3884]上帝与集合的正确用法(欧拉定理,数论) 题面 BZOJ 题解 我们有欧拉定理: 当\(b \perp p\)时 \[a^b≡a^{b\%\varphi(p)}\pmod p \] ...

  3. 【洛谷1026】【NOIP2001】统计单词个数

    题面 题目描述 给出一个长度不超过200的由小写英文字母组成的字母串(约定;该字串以每行20个字母的方式输入,且保证每行一定为20个).要求将此字母串分成k份(1<k<=40),且每份中包 ...

  4. [Shoi2007]Vote 善意的投票

    题目描述 幼儿园里有n个小朋友打算通过投票来决定睡不睡午觉.对他们来说,这个问题并不是很重要,于是他们决定发扬谦让精神.虽然每个人都有自己的主见,但是为了照顾一下自己朋友的想法,他们也可以投和自己本来 ...

  5. Spring Data(二)查询

    Spring Data(二)查询 接着上一篇,我们继续讲解Spring Data查询的策略. 查询的生成 查询的构建机制对于Spring Data的基础是非常有用的.构建的机制将截断前缀find-By ...

  6. Linux Centos 下安装软件 三种方式(转)

    Linux学习的路还很远呢,各位码农,新年快乐哈! 1)一种是软件的源代码,您需要自己动手编译它.这种软件安装包通常是用gzip压缩过的tar包(后缀为.tar.gz). 2)另一种是软件的可执行程序 ...

  7. Shiro入门这篇就够了【Shiro的基础知识、回顾URL拦截】

    前言 本文主要讲解的知识点有以下: 权限管理的基础知识 模型 粗粒度和细粒度的概念 回顾URL拦截的实现 Shiro的介绍与简单入门 一.Shiro基础知识 在学习Shiro这个框架之前,首先我们要先 ...

  8. spark source code 分析之ApplicationMaster overview(yarn deploy client mode)

    一直不是很清楚ApplicationMaster的作用,尤其是在yarn client mode和cluster mode的区别 网上有一些非常好的资料,请移步: https://blog.cloud ...

  9. 配置puppet的主机端和客户端的自动认证

    配置puppet的主机端和客户端的自动认证 author:headsen  chen    2017-11-01  17:44:56 个人原创,转载请注明作者,出处,否则依法追究法律责任 1,先在主机 ...

  10. wpf动态增加删除控件

    我在xaml中定义了一个名字为morepictureWrapPan为WrapPanel,然后将控件添加在此WrapPanel中.由于要实现控件的删除功能,所以增加的textbox和button的名字都 ...