jwt(json-web-token)在rest中的实现–jersey
来源:互联网 发布:java培训班能就业吗 编辑:程序博客网 时间:2024/04/29 03:24
原文转载:http://blog.csdn.net/li563868273/article/details/50277359
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());@AutowiredUserService userService;@ContextServletContext 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生成tokenSignatureAlgorithm 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());@AutowiredUserService userservice;//@Context//Key key;@ContextServletContext context;@Injectjavax.inject.Provider<UriInfo> uriInfo;public static String extractJwtTokenFromAuthorizationHeader(String auth) {//Replacing "Bearer Token" to "Token" directlyreturn auth.replaceFirst("[B|b][E|e][A|a][R|r][E|e][R|r] ", "").replace(" ", "");} //重写验证过滤器@Overridepublic void filter(ContainerRequestContext containerRequestContext) throws IOException {//获取本地的私钥Key key= KeyUtil.getKey(context);//得到访问的方法 例如GET,POSTString 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;}//获取头信息中的tokenString authorizationHeader = ((ContainerRequest) containerRequestContext).getHeaderString("auth_token");//如果token为空抛出if (authorizationHeader == null) {throw new WebApplicationException(Response.Status.UNAUTHORIZED);//抛出未认证的错误}//把Bear Token换成TokenString strToken=extractJwtTokenFromAuthorizationHeader(authorizationHeader);if (TokenUtil.isValid(strToken,key)){String name=TokenUtil.getName(strToken,key);//反解出NameString[] 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角色访问。
自此实现完全完毕,demo地址https://github.com/lzggsimida123/sharebook-jersey-jwt-spring-hibernate
- jwt(json-web-token)在rest中的实现–jersey
- jwt(json-web-token)在rest中的实现--jersey
- JWT -- json web token
- JWT(JSON Web Token)
- JSON Web Token (JWT)
- jwt(json web token)
- JWT -- JSON WEB TOKEN
- JSON Web Token (JWT) 简介
- 什么是 JWT -- JSON WEB TOKEN
- JWT(JSON WEB TOKEN)概要
- 什么是 JWT -- JSON WEB TOKEN
- 什么是 JWT -- JSON WEB TOKEN
- 什么是 JWT -- JSON WEB TOKEN
- 什么是 JWT -- JSON WEB TOKEN
- 什么是 JWT -- JSON WEB TOKEN
- JWT【JSON Web Token】 简述
- JWT【JSON Web Token】 简述
- 什么是 JWT -- JSON WEB TOKEN
- Header First HTML and CSS章后bullet points总结之Chapter 9
- GreenPlum 基础操作 入门教程
- Centos7 安装sklearn gcc: error: ‘-Qunused-arguments’
- codevs 1047 邮票面值设计(dfs+背包,好题)
- SSM做一个简单的网上商城-搭建项目
- jwt(json-web-token)在rest中的实现–jersey
- 一致性Hash算法
- Linux网络编程:原始套接字的魔力【下】
- iOS--多线程NSThread--02
- VM虚拟机装centos无法自动获取IP
- JDBC数据库连接
- UVA 10457 - Magic Car(并查集)
- [Google] Round A APAC Test 2017
- lldb动态调试