Implementation of jwt (json-web-token) in rest --jersey

Implementation of jwt (json-web-token) in rest – jersey

  I will not introduce the concept of jwt here, but I have a specific introduction in my other article
  http://blog.csdn.net/li563868273/article/details/50166491

  Here I mainly introduce the implementation of jwt in jersey of java, and the implementation in springMVC is similar, just follow the example.

Specific steps to implement jwt

In general, the realization of jwt should follow his verification steps. Of course you don't have to follow this step.

1. Implement the verification address. to get the token. For example, when you log in to your information, you actually get this token. In the future, as long as this token has not expired, you don't need to get another token. This token is also used by us to determine whether we have permission to access our applications.

2. Implement the filter. We implement filters here to determine whether there is a token, and whether the token is expired or the token is incorrect (forged). Here, if it is correct, we can also write information, such as user id, role and other information into the context, and there is no need to query the information in the database in other operations.

3. Implement role control. In the resource class of jersey or springmvc, we control its role. I use a role control class RolesAllowedDynamicFeature that comes with Jersey here to control the security of role permissions.

Next, I will explain how to implement it (Note: only for Jersey), first import the maven dependency package of jwt

<dependency>
  <groupId>io.jsonwebtoken</groupId>
  <artifactId>jjwt</artifactId>
  <version>0.6.0</version>
</dependency>

Implement verification address

Generally, we use the login to obtain the token. Here, we use the POST method in HTTP and the login form to achieve this. For specific information, see the code and have detailed comments.

/**
 * 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;
}
}

The above is the verified resource class. The method to get the token is as follows:

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;
}

So far, we have generated a token and returned it to the client. The client can use the token to bring the token in the header, and then enter the filter to determine whether the token is legal.

Implementation of the filter

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);
}
}

The filter is completed so far, and the summary is: if the token is correct, filter it, and if it is incorrect, throw an unauthenticated exception.

Implementation of role control

After the filter control is completed, the access to the resource class is reached. First, we need to register
register(RolesAllowedDynamicFeature.class);//role control
This is the role access interceptor provided by Jersey, which is provided by javax.annotation.security to complete the role control.

@PermitAll()
@Path("/authentication")
public class AuthenticationResource {

  @RolesAllowed({"user","admin"})
  public void xx
}

Annotating a class with @PermitAll means that all roles are accessible.
@RolesAllowed({"user","admin"}) means to allow user role and admin role access.

Since then, the implementation has been completely completed. For the specific implementation, please refer to my github address https://github.com/lzggsimida123/sharebook-jersey-jwt-spring-hibernate

 

 

http://blog.csdn.net/li563868273/article/details/50277359

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326720023&siteId=291194637