2016-05-26 59 views
1

我有這些只讀字段,需要安全,如密碼。假設我們有一個用戶對象:Dropwizard僅在@POST上驗證字段

public class User { 
    @NotEmpty 
    @Size(max = 100) 
    private String name; 
    @NotEmpty 
    private String username; 
    @NotEmpty 
    @Email 
    private String email; 
    private String password; 

    @JsonIgnore 
    public String getPassword() { 
    return password; 
    } 

    @JsonProperty 
    public void setPassword(String password) { 
    this.password = password; 
    } 
} 

所以,這很好用;如我可以得到/張貼/放置任何我想要的,但我永遠不會收到密碼。但我也想確保當它第一次發佈時,密碼不應該是空的。如果我做

@NotEmpty 
private string password; 

然後我的PUT(編輯)請求將失敗,驗證錯誤,如果我不想更改此用戶的密碼。

有兩個解決方案,我能想到的:

繼承User類,僅創建了POST一類特殊的,可以有超過吸氣劑@NotEmpty註解。

public static class Create extends User { 
    @NotEmpty 
    @Override 
    public String getPassword() { 
    return password; 
    } 
} 

這應該一般工作,但不適合我的代碼庫,因爲它已經在CRUD資源上大大利用了繼承。我需要爲這種方法打破並重復很多事情。在資源類

2-處理驗證:

public class UserResource { 

    @POST 
    public User createUser(User user) { 
    if(user.getPassword().isEmpty()) { 
     throw new ConstraintValidation....(); 
    } 
    } 
} 

做工作,但不是那麼漂亮。特別是因爲我有這些5-10。

其他選擇?

+0

你能不能讓你自己的驗證器實現,而不是使用默認的,然後有更復雜的檢查?例如,您可以有一個驗證程序,可以檢查用戶是否存在(如果不是您正在創建),然後基於此驗證密碼。我不認爲你有權訪問驗證器中的資源類型,除非你實現了一個將你的方法類型存儲在一個threadLocal或類似的愚蠢的球衣過濾器。 – pandaadb

+0

其實,閱讀球衣信息,你可以在你的驗證器中注入UriInfo。然後,您將不會根據所調用的資源方法驗證問題。請參閱:https://jersey.java.net/documentation/latest/bean-validation.html – pandaadb

+0

啊哈,我實際上已經考慮過這一點,並檢查ConstraintValidatorContext的字段,看看我能否找到相關的東西。沒有想到球衣注射。我想這也適用於hibernate-validator,對吧?如果是這樣,你可以創建一個答案,我可以標記它。謝謝! – Natan

回答

3

除了球衣注射和自定義驗證,我找到了一個涼爽,更容易和更流暢的解決方案,我認爲您可能感興趣的,納坦:

DW支持確認團組來代替。有了這些,您可以根據自己的方法決定要註釋的內容,而無需驗證方法。你可以閱讀更多有關在這裏:

http://www.dropwizard.io/0.9.0/docs/manual/validation.html

(FWIW我用我的例子中,RC版本)。

所以,讓我們開始吧:

@Path("/hello/world") 
@Produces(MediaType.APPLICATION_JSON) 
public class HelloWorldResource { 

    @POST 
    @Path("/v1") 
    @Consumes(MediaType.APPLICATION_JSON) 
    @Produces(MediaType.APPLICATION_JSON) 
    public Response test(@Valid @Validated(V1Check.class) User user) { 
     // checks only username 
     System.out.println(user.getName()); 
     System.out.println(user.getPassword()); 

     return Response.ok().build(); 
    } 


    @POST 
    @Path("/v2") 
    @Consumes(MediaType.APPLICATION_JSON) 
    @Produces(MediaType.APPLICATION_JSON) 
    public Response test2(@Valid @Validated(V2Check.class) User user) { 
     // checks both 
     System.out.println(user.getName()); 
     System.out.println(user.getPassword()); 

     return Response.ok().build(); 
    } 
} 

這是資源類。看看我如何用@Validated註釋這兩種方法。這告訴DW要準確驗證什麼。

這裏是我的用戶等級:

public class User { 

    @JsonProperty("name") 
    private String name; 

    @JsonProperty("password") 
    private String password; 

    @NotEmpty(message="other message", groups= {V2Check.class}) 
    public String getPassword() { 
     return password; 
    } 

    public void setPassword(String password) { 
     this.password = password; 
    } 

    @NotEmpty(message="asd asd asd", groups= {V1Check.class, V2Check.class }) 
    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

    public interface V1Check {}; 
    public interface V2Check {}; 
} 

我在該類嵌入接口以及。密碼現在只被V2檢查。因此,對於您的POST方法,您需要將其添加到Validated註釋中,而get方法可以保持V1檢查並忽略密碼。

和良好的措施,啓動了我的測試:

public class Starter extends Application<Configuration> { 

    @Override 
    public void run(Configuration configuration, Environment environment) throws Exception { 
     environment.jersey().register(HelloWorldResource.class); 
    } 

    public static void main(String[] args) throws Exception { 
     new Starter().run("server", "/Users/artur/dev/repo/dw-test/src/main/resources/configuration.yaml"); 
    } 

} 

這是DW的方式來做到這一點,但是你應該能夠球衣注射添加到您的自定義驗證爲好。看起來沒有必要寫一個自定義驗證器,因爲你不需要檢查你的密碼。

這是我的捲髮。該user_json2:

{ 
    "name" : "artur" 
} 

V1,不檢查密碼:

arturk:tmp artur$ curl -XPOST "localhost:9085/hello/world/v1/" --header "Content-Type: application/json" -d @user_json2 -v 
    * Trying ::1... 
    * Connected to localhost (::1) port 9085 (#0) 
    > POST /hello/world/v1/ HTTP/1.1 
    > Host: localhost:9085 
    > User-Agent: curl/7.43.0 
    > Accept: */* 
    > Content-Type: application/json 
    > Content-Length: 19 
    > 
    * upload completely sent off: 19 out of 19 bytes 
    < HTTP/1.1 200 OK 
    < Date: Fri, 27 May 2016 09:59:22 GMT 
    < Content-Length: 0 
    < 
    * Connection #0 to host localhost left intact 

V2,檢查密碼:

arturk:tmp artur$ curl -XPOST "localhost:9085/hello/world/v2/" --header "Content-Type: application/json" -d @user_json2 -v 
* Trying ::1... 
* Connected to localhost (::1) port 9085 (#0) 
> POST /hello/world/v2/ HTTP/1.1 
> Host: localhost:9085 
> User-Agent: curl/7.43.0 
> Accept: */* 
> Content-Type: application/json 
> Content-Length: 19 
> 
* upload completely sent off: 19 out of 19 bytes 
< HTTP/1.1 400 Bad Request 
< Date: Fri, 27 May 2016 10:07:41 GMT 
< Content-Type: text/html;charset=iso-8859-1 
< Cache-Control: must-revalidate,no-cache,no-store 
< Content-Length: 251 
< 
<html> 
<head> 
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/> 
<title>Error 400 Bad Request</title> 
</head> 
<body><h2>HTTP ERROR 400</h2> 
<p>Problem accessing /hello/world/v2/. Reason: 
<pre> Bad Request</pre></p> 
</body> 
</html> 
* Connection #0 to host localhost left intact 

我希望幫助!

乾杯,

阿圖爾

+0

是的!這是一個更好的方法。我知道球衣中存在實體過濾,但不知道驗證分組。我想我已經在發行說明中看到了它,但我完全忘記了它。謝謝! – Natan