单点登录SSO----JSON Web Token(JWT)机制
JSON Web Token(JWT)机制
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.sxt</groupId><artifactId>sso-jwt</artifactId><version>1.0</version><packaging>war</packaging><dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.0.6.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.0.6.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.0.6.RELEASE</version></dependency><!-- JWT核心依赖 --><dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>3.3.0</version></dependency><!-- java开发JWT的依赖jar包。 --><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.0</version></dependency><!-- 给springmvc提供的响应扩展。@ResponseBody --><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.9.5</version></dependency><dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId><version>1.2</version></dependency><dependency><groupId>javax.servlet</groupId><artifactId>servlet-api</artifactId><version>2.5</version><scope>provided</scope></dependency><dependency><groupId>javax.servlet.jsp</groupId><artifactId>jsp-api</artifactId><version>2.2</version><scope>provided</scope></dependency></dependencies><build><pluginManagement><plugins><!-- 配置Tomcat插件 --><plugin><groupId>org.apache.tomcat.maven</groupId><artifactId>tomcat7-maven-plugin</artifactId><version>2.2</version></plugin></plugins></pluginManagement><plugins><plugin><groupId>org.apache.tomcat.maven</groupId><artifactId>tomcat7-maven-plugin</artifactId><configuration><port>80</port><path>/</path></configuration></plugin></plugins></build>
</project>
JWTSubject.java
package com.sxt.sso.commons;/*** 作为Subject数据使用。也就是payload中保存的public claims* 其中不包含任何敏感数据* 开发中建议使用实体类型。或BO,DTO数据对象。*/
public class JWTSubject {private String username;public JWTSubject() {super();}public JWTSubject(String username) {super();this.username = username;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}}
JWTUtils.java
package com.sxt.sso.commons;import java.util.Date;import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.SignatureException;/*** JWT工具*/
public class JWTUtils {// 服务器的key。用于做加解密的key数据。 如果可以使用客户端生成的key。当前定义的常亮可以不使用。private static final String JWT_SECERT = "test_jwt_secert" ;private static final ObjectMapper MAPPER = new ObjectMapper();public static final int JWT_ERRCODE_EXPIRE = 1005;//Token过期public static final int JWT_ERRCODE_FAIL = 1006;//验证不通过public static SecretKey generalKey() {try {// byte[] encodedKey = Base64.decode(JWT_SECERT); // 不管哪种方式最终得到一个byte[]类型的key就行byte[] encodedKey = JWT_SECERT.getBytes("UTF-8");SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");return key;} catch (Exception e) {e.printStackTrace();return null;}}/*** 签发JWT,创建token的方法。* @param id jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。* @param iss jwt签发者* @param subject jwt所面向的用户。payload中记录的public claims。当前环境中就是用户的登录名。* @param ttlMillis 有效期,单位毫秒* @return token, token是一次性的。是为一个用户的有效登录周期准备的一个token。用户退出或超时,token失效。* @throws Exception*/public static String createJWT(String id,String iss, String subject, long ttlMillis) {// 加密算法SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;// 当前时间。long nowMillis = System.currentTimeMillis();// 当前时间的日期对象。Date now = new Date(nowMillis);SecretKey secretKey = generalKey();// 创建JWT的构建器。 就是使用指定的信息和加密算法,生成Token的工具。JwtBuilder builder = Jwts.builder().setId(id) // 设置身份标志。就是一个客户端的唯一标记。 如:可以使用用户的主键,客户端的IP,服务器生成的随机数据。.setIssuer(iss).setSubject(subject).setIssuedAt(now) // token生成的时间。.signWith(signatureAlgorithm, secretKey); // 设定密匙和算法if (ttlMillis >= 0) { long expMillis = nowMillis + ttlMillis;Date expDate = new Date(expMillis); // token的失效时间。builder.setExpiration(expDate);}return builder.compact(); // 生成token}/*** 验证JWT* @param jwtStr* @return*/public static JWTResult validateJWT(String jwtStr) {JWTResult checkResult = new JWTResult();Claims claims = null;try {claims = parseJWT(jwtStr);checkResult.setSuccess(true);checkResult.setClaims(claims);} catch (ExpiredJwtException e) { // token超时checkResult.setErrCode(JWT_ERRCODE_EXPIRE);checkResult.setSuccess(false);} catch (SignatureException e) { // 校验失败checkResult.setErrCode(JWT_ERRCODE_FAIL);checkResult.setSuccess(false);} catch (Exception e) {checkResult.setErrCode(JWT_ERRCODE_FAIL);checkResult.setSuccess(false);}return checkResult;}/*** * 解析JWT字符串* @param jwt 就是服务器为客户端生成的签名数据,就是token。* @return* @throws Exception*/public static Claims parseJWT(String jwt) throws Exception {SecretKey secretKey = generalKey();return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(jwt).getBody(); // getBody获取的就是token中记录的payload数据。就是payload中保存的所有的claims。}/*** 生成subject信息* @param subObj - 要转换的对象。* @return java对象->JSON字符串出错时返回null*/public static String generalSubject(Object subObj){try {return MAPPER.writeValueAsString(subObj);} catch (JsonProcessingException e) {e.printStackTrace();return null;}}}
JWTResponseData.java
package com.sxt.sso.commons;/*** 发送给客户端的数据对象。* 商业开发中,一般除特殊请求外,大多数的响应数据都是一个统一类型的数据。* 统一数据有统一的处理方式。便于开发和维护。*/
public class JWTResponseData {private Integer code;// 返回码,类似HTTP响应码。如:200成功,500服务器错误,404资源不存在等。private Object data;// 业务数据private String msg;// 返回描述private String token;// 身份标识, JWT生成的令牌。public Integer getCode() {return code;}public void setCode(Integer code) {this.code = code;}public Object getData() {return data;}public void setData(Object data) {this.data = data;}public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}public String getToken() {return token;}public void setToken(String token) {this.token = token;}}
JWTResult.java
package com.sxt.sso.commons;import io.jsonwebtoken.Claims;/*** 结果对象。*/
public class JWTResult {/*** 错误编码。在JWTUtils中定义的常量。* 200为正确*/private int errCode;/*** 是否成功,代表结果的状态。*/private boolean success;/*** 验证过程中payload中的数据。*/private Claims claims;public int getErrCode() {return errCode;}public void setErrCode(int errCode) {this.errCode = errCode;}public boolean isSuccess() {return success;}public void setSuccess(boolean success) {this.success = success;}public Claims getClaims() {return claims;}public void setClaims(Claims claims) {this.claims = claims;}}
JWTController.java
package com.sxt.sso.controller;import java.util.UUID;import javax.servlet.http.HttpServletRequest;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;import com.sxt.sso.commons.JWTResponseData;
import com.sxt.sso.commons.JWTResult;
import com.sxt.sso.commons.JWTSubject;
import com.sxt.sso.commons.JWTUsers;
import com.sxt.sso.commons.JWTUtils;@Controller
public class JWTController {@RequestMapping("/testAll")@ResponseBodypublic Object testAll(HttpServletRequest request){String token = request.getHeader("Authorization");JWTResult result = JWTUtils.validateJWT(token);JWTResponseData responseData = new JWTResponseData();if(result.isSuccess()){responseData.setCode(200);responseData.setData(result.getClaims().getSubject());// 重新生成token,就是为了重置token的有效期。String newToken = JWTUtils.createJWT(result.getClaims().getId(), result.getClaims().getIssuer(), result.getClaims().getSubject(), 1*60*1000);responseData.setToken(newToken);return responseData;}else{responseData.setCode(500);responseData.setMsg("用户未登录");return responseData;}}@RequestMapping("/login")@ResponseBodypublic Object login(String username, String password){JWTResponseData responseData = null;// 认证用户信息。本案例中访问静态数据。if(JWTUsers.isLogin(username, password)){JWTSubject subject = new JWTSubject(username);String jwtToken = JWTUtils.createJWT(UUID.randomUUID().toString(), "sxt-test-jwt", JWTUtils.generalSubject(subject), 1*60*1000);responseData = new JWTResponseData();responseData.setCode(200);responseData.setData(null);responseData.setMsg("登录成功");responseData.setToken(jwtToken);}else{responseData = new JWTResponseData();responseData.setCode(500);responseData.setData(null);responseData.setMsg("登录失败");responseData.setToken(null);}return responseData;}}
index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript">function login(){var username = $("#username").val();var password = $("#password").val();var params = "username="+username+"&password="+password;$.ajax({'url' : '${pageContext.request.contextPath }/login','data' : params,'success' : function(data){if(data.code == 200){var token = data.token;// web storage的查看 - 在浏览器的开发者面板中的application中查看。// local storage - 本地存储的数据。 长期有效的。// session storage - 会话存储的数据。 一次会话有效。var localStorage = window.localStorage; // 浏览器提供的存储空间。 根据key-value存储数据。localStorage.token = token;}else{alert(data.msg);}}});
}function setHeader(xhr){ // XmlHttpRequestxhr.setRequestHeader("Authorization",window.localStorage.token);
}function testLocalStorage(){$.ajax({'url' : '${pageContext.request.contextPath}/testAll','success' : function(data){if(data.code == 200){window.localStorage.token = data.token;alert(data.data);}else{alert(data.msg);}},'beforeSend' : setHeader});
}</script>
</head>
<body ><center><table><caption>登录测试</caption><tr><td style="text-align: right; padding-right: 5px">登录名:</td><td style="text-align: left; padding-left: 5px"><input type="text" name="username" id="username"/></td></tr><tr><td style="text-align: right; padding-right: 5px">密码:</td><td style="text-align: left; padding-left: 5px"><input type="text" name="password" id="password"/></td></tr><tr><td style="text-align: right; padding-right: 5px" colspan="2"><input type="button" value="登录" onclick="login();" /></td></tr></table></center><input type="button" value="testLocalStorage" onclick="testLocalStorage();"/>
</body>
</html>
单点登录SSO----JSON Web Token(JWT)机制相关推荐
- JSON Web Token (JWT),服务端信息传输安全解决方案
转载自 JSON Web Token (JWT),服务端信息传输安全解决方案 JWT介绍 JSON Web Token(JWT)是一种开放标准(RFC 7519),它定义了一种紧凑独立的基于JSON对 ...
- JSON Web Token (JWT)生成Token及解密实战
转载自 JSON Web Token (JWT)生成Token及解密实战 昨天讲解了JWT的介绍.应用场景.优点及注意事项等,今天来个JWT具体的使用实践吧. 从JWT官网支持的类库来看,jjwt是J ...
- php jwt token 解析,JSON Web Token(JWT)入坑详解
JSON Web Token(JWT)入坑详解 龙行 PHP 2019-6-17 1651 0评论 /** JWT生成类 **/ class Jwt { private $al ...
- Json web token (JWT) golang实现
Json web token (JWT) eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG ...
- 单点登录SSO解决方案之SpringSecurity+JWT实现
通过前面几天文章我们详细的介绍了SpringSecurity的使用,本文我们来看下,结合JWT来实现单点登录操作. 一.什么是单点登陆 单点登录(Single Sign On),简称为 SSO ...
- (json web token)JWT攻击
前记 最近国赛+校赛遇到两次json web token的题,发现自己做的并不算顺畅,于是有了这篇学习文章. 为什么要使用Json Web Token Json Web Token简称jwt 顾名思义 ...
- JSON Web Token (JWT)笔记(token实现单点登录功能)
文章目录 前情提要 cookie(储存在用户本地终端上的数据) Cookie特点: session(web服务端内存) cookie和session 单点登录(只登录一次,可使用账号下全部服务)三种方 ...
- jwttoken解码_使用 JSON WEB TOKEN (jwt) 验证
一.什么JSON Web Tokens? JSON Web Tokens是一种开放的行业标准 RFC 7519方法,用于在双方之间安全地表示索赔. JWT.IO允许您解码,验证和生成JWT.其中.J ...
- JSON Web Token(JWT)对比Opaque Token
身份验证通常用来验证某人或某事是否如它所说的那样是谁或者是什么. 身份验证技术通过测试查看用户的凭据是否与经过身份验证的用户数据库或服务器中的凭据相匹配,从而提供设备访问控制. 基于token的身份验 ...
- 用户登入身份验证,手机app登入身份验证,TokenAuth身份验证,JSON Web Token(JWT)身份验证
JJWT身份验证 1.pom依赖: <dependency ...
最新文章
- servlet单实例多线程 ---线程安全问题是由实例变量造成的,只要在Servlet里面的任何方法里面都不使用实例变量,那么该Servlet就是线程安全的。(所有建议不要在servlet中定义成员变
- 内存写越界导致破环堆结构引起的崩溃问题定位经验[如报错malloc(): memory corruption或free(): invalid next size]...
- 【设计模式】享元模式 实现 ( 实现流程 | 抽象享元类 | 具体享元类 | 享元工厂 | 用户调用 | 代码模板 )
- movavi video suite2020中文版
- python表格对齐_python str.format 中文对齐的细节问题,
- win10 Java JDK环境变量配置
- openstack 在线repo
- chrome调试本地项目, 引用本地javascript文件
- 苹果折叠iPhone终于有动作了!已送样至富士康,售价将超万元
- action链接html,如何使用@ html.actionlink删除链接文本
- 新IT运维时代 | Docker运维之最佳实践-上篇
- layui table勾选框的修改_layui表格(Table)下添加可更新拉选择框select
- quartus仿真系列1:74163的计数功能
- 项目总结(四)邮件订阅
- 操作系统原理,Windows线程调度,引发线程调度的事件,Windows线程优先级,Windows时间配额,Windows线程调度策略,Windows优先级提升事件
- android qq输入法表情,QQ输入法-问题反馈
- CarPlay搭载下滑/华为HiCar目标未达成,车机互联赛道「难」
- Python列表基础--仅index()获取元素全部索引
- meta中的http-equiv = X-UA-Compatible
- python导入库关键词_怎么样导入RobotFramework 自定义关键字(库文件)
热门文章
- Linux学习16 软件包和启动项管理
- 使用dd命令克隆整个系统
- 网页版番茄时钟的制作——Pomodoro Clock
- 计算机指令包括哪2部分,机器指令分为哪几部分
- CoordConv:An intriguing failing of convolutional neural networks and the CoordConv solution
- burpSuite之安装+配置代理+安装证书抓取https
- 2019年甘肃省普通高等学校高职(专科)升本科考试招生工作实施办法
- 华为p8 root android6,华为p8青春版root教程【图解】
- 如何快速制作证件照并压缩到100K?
- SSL证书的申请流程