jwt(json-web-token)在rest中的实现–jersey
在这里我就不介绍jwt的概念,在我的另外一篇里面有具体的介绍
http://blog.csdn.net/li563868273/article/details/50166491
我这里主要介绍jwt在java的jersey中的实现,在springMVC中实现也大同小异,仿照过来就行了。
实现jwt的具体步骤
总的来说实现jwt要跟着他的验证步骤来。当然也不一定要按照这个步骤。
1.实现验证地址。来获取token。举个例子,你登陆自己的信息的时候其实就是获取这个token,以后只要这个token没有过期就不需要再获取token了,这个token也是我们以后靠他来判断是否有权限访问我们的所用应用。
2.实现过滤器。我们这里实现了过滤器来判断是否有token,以及token是否过期或者token不正确(伪造的)。在这里如果正确我们也可以把信息,比如用户id,角色等信息写入上下文,在其他操作的时候就不需要在此再数据库中查询信息了。
3.实现角色控制。在jersey或springmvc的资源类中,我们对其角色控制,我这里使用的时Jersey自带的一个角色控制类RolesAllowedDynamicFeature,来控制角色权限安全。
接下来具体讲解怎么实现(注:仅针对Jersey),先导入jwt的maven依赖包
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.6.0</version>
</dependency>
实现验证地址
一般我们采用登陆的来获取token,这里用HTTP中的POST方法,和登陆表单来实现,具体信息看代码,有详细注释
/**
* Created by lizhaoz on 2015/11/30.
*/
//~--- non-JDK imports --------------------------------------------------------
import com.lclizhao.sharebook.daomain.Token;
import com.lclizhao.sharebook.daomain.User;
import com.lclizhao.sharebook.service.UserService;
import com.lclizhao.sharebook.utils.KeyUtil;
import com.lclizhao.sharebook.utils.TokenUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
//~--- JDK imports ------------------------------------------------------------
import java.util.Calendar;
import java.util.Date;
import javax.annotation.security.PermitAll;
import javax.servlet.ServletContext;
import javax.validation.constraints.NotNull;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
/**
* @Name:
* @Author: lizhao(作者)
* @Version: V1.00 (版本号)
* @Create Date: 2015-11-26(创建日期)
* @Description:
* 验证资源类
*/
@PermitAll()
@Path("/authentication")
public class AuthenticationResource {
private final static Logger logger = LogManager.getLogger(AuthenticationResource.class.getName());
@Autowired
UserService userService;
@Context
ServletContext context;
/**
* author:Lizhao
* Date:15/12/12
* version:1.0
*
* @param username
* @param password
*
* @return
*/
@POST
@Produces("application/json")
@Consumes("application/x-www-form-urlencoded")
// 进入验证方法的接口
public Response authenticateUser(@NotNull
@FormParam("telphone") String username, @NotNull
@FormParam("password") String password) {
// 设置这个token的生命时间
Date expiry = getExpiryDate(30 * 24 * 60);// 30天的有效日期
// 验证账号密码是否正确
User user = authenticate(username, password);
//使用Token工具类得到token,生成的策略是利用用户的姓名,到期时间,和私钥
//我这里使用的时Key key =MacProvider.generateKey(SignatureAlgorithm.HS512);
//HS512签名算法,必须保存生成的这个key到硬盘上,不然下次会出错,因为是hash算法,所以会变
//这个私钥可以理解为一把锁孔,可以依据这个锁孔来生成钥匙也就是token,但要进入这个门必须要匹配这个锁孔
String jwtString = TokenUtil.getJWTString(username, expiry, KeyUtil.getKey(context));
//这是token的实体化类,用来返回给用户
Token token = new Token();
token.setAuthToken(jwtString);
token.setExpires(expiry);
return Response.ok(token).build();
}
/**
* author:Lizhao
* Date:15/12/12
* version:1.0
*
* @param minutes
*
* @return
*/
private Date getExpiryDate(int minutes) {
// 根据当前日期,来得到到期日期
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date());
calendar.add(Calendar.MINUTE, minutes);
return calendar.getTime();
}
/**
* author:Lizhao
* Date:15/12/12
* version:1.0
*
* @param username
* @param password
*
* @return
*
* @throws NotAuthorizedException
* 在这个方法中实现验证用户账号密码,如果错误就抛出未验证信息,如果正确就返回一个用户
*/
private User authenticate(String username, String password) throws NotAuthorizedException {
User user = null;
user = userService.findUserByTel(username);
if (user == null) {
logger.info("Invalid username '" + username + "' ");
throw new NotAuthorizedException("Invalid telpone '" + username + "' ");
}
// we need to actually test the Hash not the password, we should never store the password in the database.
if (user.getPassword().equals(password)) {
logger.info("USER AUTHENTICATED");
} else {
logger.info("USER NOT AUTHENTICATED");
throw new NotAuthorizedException("Invalid username or password");
}
return user;
}
}
以上是验证的资源类,对于得到token的方法如下所示:
public static String getJWTString(String tel,Date expires,Key key){
if (tel == null) {
throw new NullPointerException("null username is illegal");
}
if (expires == null) {
throw new NullPointerException("null expires is illegal");
}
if (key == null) {
throw new NullPointerException("null key is illegal");
}
//用签名算法HS256和私钥key生成token
SignatureAlgorithm signatureAlgorithm =SignatureAlgorithm.HS256;
String jwtString = Jwts.builder()
.setIssuer("Jersey-Security-Basic")//设置发行人
.setSubject(tel)//设置抽象主题
.setAudience("user")//设置角色
.setExpiration(expires)//过期时间
.setIssuedAt(new Date())//设置现在时间
.setId("1")//版本1
.signWith(signatureAlgorithm,key)
.compact();
return jwtString;
}
至此我们生成了token,返回给客户端,客户端可以利用这个token在头中带上这个token,便可以进入过滤器判断是否这个token合法。
过滤器的实现
import com.lclizhao.sharebook.daomain.User;
import com.lclizhao.sharebook.service.UserService;
import com.lclizhao.sharebook.utils.KeyUtil;
import com.lclizhao.sharebook.utils.TokenUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.glassfish.jersey.server.ContainerRequest;
import org.springframework.beans.factory.annotation.Autowired;
import javax.annotation.Priority;
import javax.inject.Inject;
import javax.servlet.ServletContext;
import javax.ws.rs.Priorities;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.ext.Provider;
import java.io.IOException;
import java.security.Key;
/**
* @Name:
* @Author: lizhao(作者)
* @Version: V1.00 (版本号)
* @Create Date: 2015-11-26(创建日期)
* @Description:
*/
@Provider
@Priority(Priorities.AUTHENTICATION)//优先级最高
//实现该拦截器借口
//@Provider可以自动注册
public class JWTSecurityFilter implements ContainerRequestFilter{
final static Logger logger = LogManager.getLogger(JWTSecurityFilter.class.getName());
@Autowired
UserService userservice;
//@Context
//Key key;
@Context
ServletContext context;
@Inject
javax.inject.Provider<UriInfo> uriInfo;
public static String extractJwtTokenFromAuthorizationHeader(String auth) {
//Replacing "Bearer Token" to "Token" directly
return auth.replaceFirst("[B|b][E|e][A|a][R|r][E|e][R|r] ", "").replace(" ", "");
}
//重写验证过滤器
@Override
public void filter(ContainerRequestContext containerRequestContext) throws IOException {
//获取本地的私钥
Key key= KeyUtil.getKey(context);
//得到访问的方法 例如GET,POST
String method = containerRequestContext.getMethod().toLowerCase();
//得到访问路径
String path = ((ContainerRequest) containerRequestContext).getPath(true).toLowerCase();
//get application.wadl和application.wadl/xsd0.xsd不需要验证,post验证过滤,注册过滤。
if (("get".equals(method) && ("application.wadl".equals(path) || "application.wadl/xsd0.xsd".equals(path)))
|| ("post".equals(method) &&( "authentication".equals(path)||"regist".equals(path)))||("get".equals(method) && "user".equals(path))) {
// pass through the filter.
containerRequestContext.setSecurityContext(new SecurityContextAuthorizer(uriInfo,new AuthorPricinple("pass"), new String[]{"pass"}));
return;
}
//获取头信息中的token
String authorizationHeader = ((ContainerRequest) containerRequestContext).getHeaderString("auth_token");
//如果token为空抛出
if (authorizationHeader == null) {
throw new WebApplicationException(Response.Status.UNAUTHORIZED);//抛出未认证的错误
}
//把Bear Token换成Token
String strToken=extractJwtTokenFromAuthorizationHeader(authorizationHeader);
if (TokenUtil.isValid(strToken,key)){
String name=TokenUtil.getName(strToken,key);//反解出Name
String[] roles=TokenUtil.getRoles(strToken,key);//反解出角色
int version=TokenUtil.getVersion(strToken,key);//得到版本
if(name !=null&&roles.length!=0&&version!=-1){
User user=userservice.findUserByTel(name);
if(user!=null){
containerRequestContext.setSecurityContext(new SecurityContextAuthorizer(uriInfo,new AuthorPricinple(name), new String[]{"user"}));
return;
}
else{
logger.info("User not found " + name);
}
}
else {
logger.info("name, roles or version missing from token");
}
}
else {
logger.info("token is invalid");
}
throw new WebApplicationException(Response.Status.UNAUTHORIZED);
}
}
过滤器至此完成,总结就是:token正确就过滤,如果不正确就抛出未认证异常。
角色控制的实现
过滤器控制完成了就到了资源类的访问,首先我们要注册
register(RolesAllowedDynamicFeature.class);//角色控制
这是Jersey提供的角色访问拦截器,利用javax.annotation.security提供的来完成角色控制。
@PermitAll()
@Path("/authentication")
public class AuthenticationResource {
@RolesAllowed({"user","admin"})
public void xx
}
@PermitAll在类上注解意思是所有角色均可访问。
@RolesAllowed({“user”,”admin”}) 意思允许user角色和admin角色访问。
自此实现完全完毕,具体实现参考我的github地址https://github.com/lzggsimida123/sharebook-jersey-jwt-spring-hibernate
http://blog.csdn.net/li563868273/article/details/50277359
相关推荐
JWT是json web token缩写。它将用户信息加密到token里,服务器不保存任何用户信息。服务器通过使用保存的密钥验证token的正确性,只要正确即通过验证。基于token的身份验证可以替代传统的cookie+session身份验证方法...
JSON Web Token 实现分享 JSON Web Token(JWT)是一种基于 token 的身份验证机制,它可以提供一种无状态、可扩展、安全的身份验证方式。下面将详细介绍 JWT 的实现和使用。 为什么需要 Web Token? 在服务器端...
JWT(json web token)是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准。 JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源。比如用在用户登录上...
标题 "sping-boot-shiro-jwt-redis-refreshtoken.zip" 暗示这是一个关于Spring Boot、Shiro、JWT(JSON Web Token)以及Redis整合的项目,用于实现权限管理和安全认证,特别是涉及到Token的自动刷新功能。...
使用JWT身份验证的json-server的假REST API。 实现的端点:登录,注册 安装 $ npm install $ npm run start-auth 可能需要跑步 npm audit fix 如何登录/注册? 您可以通过向以下站点发送POST请求来登录/注册 POST...
使用JWT加密和解密文本使用JWT的加密和解密技术在命令提示符下的应用程序的根目录中运行以下命令。 节点服务器您可以在控制台中看到加密的文本和解密的文本您可以使用加密技术,让我们看一下[Crypto-encryption-...
今天我们要关注的是一个名为`py-auth0-jwt-rest-0.1.2.tar.gz`的压缩包,它在PyPI官网上可以找到。这个包主要用于处理Auth0的JWT(JSON Web Token)验证以及相关的RESTful API操作。 JWT是一种轻量级的身份验证和...
JWT是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,...
JSON Web Token(JWT)是一种开放的标准(RFC 7519),定义了一种紧凑的、自包含的方式来安全地在各方之间传输信息作为一个JSON对象。这个信息可以被验证和信任,因为它是数字签名的。在JavaScript(JS)环境中,JWT...
JSON Web Token(JWT)是一种广泛使用的轻量级身份验证和授权机制,主要应用于Web应用程序和服务之间的安全通信。JWT通过在客户端和服务器之间传递令牌来携带信息,这些信息经过签名,可以确保数据的完整性和不可...
在`go-json-rest`中,还可以轻松地添加身份验证和授权机制,比如JWT(JSON Web Tokens)或者自定义的认证中间件。此外,框架还支持自定义错误处理和自定义数据格式的序列化与反序列化。 总结来说,`go-json-rest`为...
json-web-token-nodejs-mysql-api-rest 带有身份验证 Json Web 令牌、Node Js 和 MySQL 的 API-REST,并请求 http get、post、put 和 delete。结构: 结构简单、描述性强! const express = require ( "express" ) ;...
wp-api-jwt-auth, 添加 JSON Web令牌( JWT ) 认证到 WP REST API的简单插件 REST API的JWT身份验证添加 JSON令牌( JWT ) 认证到 REST API的简单插件。要了解有关JSON网络令牌的更多信息,请访问 http://jwt.io 。...
下面将详细介绍如何在Spring Boot中整合JWT、Shiro和Redis实现Token自动刷新。 JWT是一种轻量级的身份验证机制,它通过在客户端存储一个包含用户信息的令牌,每次请求时都将这个令牌发送到服务器进行验证。JWT由三...
JSON Web Token(JWT)是一种开放的标准(RFC 7519),定义了一种紧凑的、自包含的方式来安全地在各方之间传输信息作为一个JSON对象。这个信息可以被验证和信任,因为它是数字签名的。JWT可用于身份验证、授权,以及...
这是一个基于Rust编程语言构建的后端应用程序,利用了Actix-web、Diesel和JWT(JSON Web Tokens)技术,实现了RESTful API接口的创建、读取、更新和删除(CRUD)功能。以下是对这些技术及其在项目中的应用的详细解释...
Ruby中的JSON Web令牌及其家族(JSON Web签名,JSON Web加密和JSON Web密钥) 安装 gem install json-jwt 资源 在GitHub上查看源代码( ) 在GitHub上报告问题( ) GitHub上的文档( ) 例子 require 'json/jwt'...
在本项目"Webapi_JWT_Authentication-master"中,我们将探讨如何实现这一机制。 首先,WebAPI是ASP.NET框架的一部分,它用于构建RESTful服务,允许客户端和服务器之间进行数据交换。RESTful服务通常基于HTTP协议,...
SpringSecurity-JWT-VERSION2(AccessToken和RefreshToken) version1太复杂,无法优化。accessToken refreshToken流安全登录处理流程详细说明转到博客文章JWT异常处理安全异常处理(AuthenticationEntryPoint,...