2016-05-26 33 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