2017-03-09 91 views
0

我正在開發REST API,並決定使用JWT進行身份驗證/安全性。有一個服務可以處理登錄驗證,並有一個過濾器綁定到每個需要驗證的服務。如何爲JWT生成和訪問密鑰

LoginService.java:

@Path("login") 
public class LoginService { 

    private final static long EXPIRATION_TIME = 60000; 

@POST 
@Produces("application/json") 
@Consumes("application/json") 
public Response authenticateUser(Credentials c) { 
    Users login; 
    UsersDAO u = new UsersDAO(); 
    try { 
     login = u.getAuthentication(c); 

     String token = generateToken(login.getIdUser(), login.getLogin(), login.getRole()); 

     // Return the token on the response 
     return Response.ok().header(AUTHORIZATION, "Bearer " + token).build(); 
    } catch (Exception e){ 
     System.out.println("Exception: " + e.toString()); 
     return Response.status(Response.Status.UNAUTHORIZED).build(); 
    }  
} 

private String generateToken(int id, String login, int role) { 
    long nowMillis = System.currentTimeMillis(); 
    Date now = new Date(nowMillis); 

    //TODO generate key (or retrieve it from file/database?) 
    Key key; 

    String jwtToken = Jwts.builder() 
      .setSubject(login) 
      .setIssuer("my_company") 
      .setIssuedAt(now) 
      .setExpiration(new Date(nowMillis + EXPIRATION_TIME)) 
      .claim("role", role) 
      .signWith(SignatureAlgorithm.HS512, key) 
      .compact(); 
    return jwtToken; 
    } 

JWTTokenFilter.java:

@Provider 
@JWTTokenNeeded 
@Priority(Priorities.AUTHENTICATION) 
public class JWTTokenFilter implements ContainerRequestFilter { 

    @Override 
    public void filter(ContainerRequestContext requestContext) throws IOException { 

    String authorizationHeader = requestContext.getHeaderString(HttpHeaders.AUTHORIZATION); 

    String token = authorizationHeader.substring("Bearer".length()).trim(); 

    try {  
     // TODO generate key (or retrieve it from file/database?) 
     Key key; 
     Jwts.parser().setSigningKey(key).parseClaimsJws(token); 

    } catch (Exception e) { 
     requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).build()); 
    } 
    } 
} 

我一直在做一些研究,但我仍然不知道如何管理密鑰生成/驗證。我的疑惑:

  • 如果我在驗證時創建密鑰,我怎麼能通過這個相同的密鑰到過濾器?我見過一些代碼示例,其中使用隨機數進行身份驗證和驗證時都生成密鑰,這對我來說沒有意義,因爲生成的密鑰不會相同。我在那裏錯過了什麼?
  • 其他選項可以將密鑰存儲在文件系統中,因此驗證和驗證過程都可以訪問相同的密鑰。這會帶來什麼壞處(如果有的話)?有什麼好的庫或框架來管理文件系統(甚至數據庫)中的密鑰生成和訪問?

請注意,我不想將密鑰傳遞給客戶端,因此他們必須稍後進行身份驗證,以刷新令牌,因爲他們無法訪問到期日期。 This主題不適合我的情況,和this是相當完整的,但沒有帶來任何例子

回答

1

這聽起來像你想重新發明輪子。 OpenID連接爲您提供了使用JWT的選項,但是如果您堅持自行開發,那麼MitreID連接(https://github.com/mitreid-connect/)不是一個糟糕的地方,可以查看提供JWT的開源java openid連接實現。

2

如果你在運行時生成對稱密鑰,你可以在過濾器和使用登錄班春注射之間或一個靜態變量

共享但是考慮到重新啓動服務器將所有的無效發行JWT。如果這不是所期望的行爲,你需要堅持關鍵在屬性文件或數據庫

使用Jjwt,你可以這樣做:

//generate a random HMAC 
Key key = MacProvider.generateKey(SignatureAlgorithm.HS256); 

//Get the key data 
byte keyData[]= key.getEncoded(); 
//Store data in a file... 

//Build key 
Key key = new SecretKeySpec(keyData, SignatureAlgorithm.HS256.getJcaName());