原文: https://howtodoinjava.com/jersey/jersey-rest-security/

在此 Jersey rest 安全示例中,我们将学习通过基本认证保护 Jersey REST API 的安全。 这将强制每个用户提供用户名/密码以认证到门户。 另外,用户还必须具有一定级别的角色。 我从为 RESTEasy API 安全性创建的另一个示例扩展了此示例,并使用ContainerRequestFilter实现在用户登陆实际的 REST API 之前验证其访问权限。

  1. Table of Contents
  2. 1\. Create request authentication filter
  3. 2\. Register AuthenticationFilter with ResourceConfig
  4. 3\. Secure REST APIs
  5. 4\. Test Jersey AuthenticationFilter

1. 创建请求认证过滤器

我们知道 JAX-RS 2.0 具有用于处理请求前和请求的过滤器,因此我们将使用ContainerRequestFilter接口。 在此过滤器中,我们将获取请求尝试访问的方法的详细信息。

我们将找出该方法上所有与安全性相关的配置,并在此过滤器中验证所有内容,例如,注解,例如@PermitAll@DenyAll@RolesAllowed

根据方法上的注解,我们将决定是通过还是阻止请求。

  1. package com.howtodoinjava.jersey.provider;
  2. import java.lang.reflect.Method;
  3. import java.util.Arrays;
  4. import java.util.HashSet;
  5. import java.util.List;
  6. import java.util.Set;
  7. import java.util.StringTokenizer;
  8. import javax.annotation.security.DenyAll;
  9. import javax.annotation.security.PermitAll;
  10. import javax.annotation.security.RolesAllowed;
  11. import javax.ws.rs.container.ContainerRequestContext;
  12. import javax.ws.rs.container.ResourceInfo;
  13. import javax.ws.rs.core.Context;
  14. import javax.ws.rs.core.MultivaluedMap;
  15. import javax.ws.rs.core.Response;
  16. import javax.ws.rs.ext.Provider;
  17. import org.glassfish.jersey.internal.util.Base64;
  18. /**
  19. * This filter verify the access permissions for a user
  20. * based on username and passowrd provided in request
  21. * */
  22. @Provider
  23. public class AuthenticationFilter implements javax.ws.rs.container.ContainerRequestFilter
  24. {
  25. @Context
  26. private ResourceInfo resourceInfo;
  27. private static final String AUTHORIZATION_PROPERTY = "Authorization";
  28. private static final String AUTHENTICATION_SCHEME = "Basic";
  29. @Override
  30. public void filter(ContainerRequestContext requestContext)
  31. {
  32. Method method = resourceInfo.getResourceMethod();
  33. //Access allowed for all
  34. if( ! method.isAnnotationPresent(PermitAll.class))
  35. {
  36. //Access denied for all
  37. if(method.isAnnotationPresent(DenyAll.class))
  38. {
  39. requestContext.abortWith(Response.status(Response.Status.FORBIDDEN)
  40. .entity("Access blocked for all users !!").build(););
  41. return;
  42. }
  43. //Get request headers
  44. final MultivaluedMap<String, String> headers = requestContext.getHeaders();
  45. //Fetch authorization header
  46. final List<String> authorization = headers.get(AUTHORIZATION_PROPERTY);
  47. //If no authorization information present; block access
  48. if(authorization == null || authorization.isEmpty())
  49. {
  50. requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED)
  51. .entity("You cannot access this resource").build());
  52. return;
  53. }
  54. //Get encoded username and password
  55. final String encodedUserPassword = authorization.get(0).replaceFirst(AUTHENTICATION_SCHEME + " ", "");
  56. //Decode username and password
  57. String usernameAndPassword = new String(Base64.decode(encodedUserPassword.getBytes()));;
  58. //Split username and password tokens
  59. final StringTokenizer tokenizer = new StringTokenizer(usernameAndPassword, ":");
  60. final String username = tokenizer.nextToken();
  61. final String password = tokenizer.nextToken();
  62. //Verifying Username and password
  63. System.out.println(username);
  64. System.out.println(password);
  65. //Verify user access
  66. if(method.isAnnotationPresent(RolesAllowed.class))
  67. {
  68. RolesAllowed rolesAnnotation = method.getAnnotation(RolesAllowed.class);
  69. Set<String> rolesSet = new HashSet<String>(Arrays.asList(rolesAnnotation.value()));
  70. //Is user valid?
  71. if( ! isUserAllowed(username, password, rolesSet))
  72. {
  73. requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED)
  74. .entity("You cannot access this resource").build(););
  75. return;
  76. }
  77. }
  78. }
  79. }
  80. private boolean isUserAllowed(final String username, final String password, final Set<String> rolesSet)
  81. {
  82. boolean isAllowed = false;
  83. //Step 1\. Fetch password from database and match with password in argument
  84. //If both match then get the defined role for user from database and continue; else return isAllowed [false]
  85. //Access the database and do this part yourself
  86. //String userRole = userMgr.getUserRole(username);
  87. if(username.equals("howtodoinjava") && password.equals("password"))
  88. {
  89. String userRole = "ADMIN";
  90. //Step 2\. Verify user role
  91. if(rolesSet.contains(userRole))
  92. {
  93. isAllowed = true;
  94. }
  95. }
  96. return isAllowed;
  97. }
  98. }

2. 向ResourceConfig注册AuthenticationFilter

现在,您需要在ResourceConfig实例上方注册过滤器。 因此,创建一个如下所示的实例:

  1. package com.howtodoinjava.jersey;
  2. import org.glassfish.jersey.filter.LoggingFilter;
  3. import org.glassfish.jersey.server.ResourceConfig;
  4. import com.howtodoinjava.jersey.provider.AuthenticationFilter;
  5. import com.howtodoinjava.jersey.provider.GsonMessageBodyHandler;
  6. public class CustomApplication extends ResourceConfig
  7. {
  8. public CustomApplication()
  9. {
  10. packages("com.howtodoinjava.jersey");
  11. register(LoggingFilter.class);
  12. register(GsonMessageBodyHandler.class);
  13. //Register Auth Filter here
  14. register(AuthenticationFilter.class);
  15. }
  16. }

并将此资源配置添加到web.xml文件中。

  1. <!DOCTYPE web-app PUBLIC
  2. "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
  3. "http://java.sun.com/dtd/web-app_2_3.dtd" >
  4. <web-app>
  5. <display-name>Archetype Created Web Application</display-name>
  6. <servlet>
  7. <servlet-name>jersey-serlvet</servlet-name>
  8. <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
  9. <init-param>
  10. <param-name>javax.ws.rs.Application</param-name>
  11. <param-value>com.howtodoinjava.jersey.CustomApplication</param-value>
  12. </init-param>
  13. <load-on-startup>1</load-on-startup>
  14. </servlet>
  15. <servlet-mapping>
  16. <servlet-name>jersey-serlvet</servlet-name>
  17. <url-pattern>/rest/*</url-pattern>
  18. </servlet-mapping>
  19. </web-app>

3. 安全的 REST API

现在是时候保护 REST API 了。 如下使用标准的 JAX-RS 注解。

  1. @Path("/employees")
  2. public class JerseyService
  3. {
  4. @RolesAllowed("ADMIN")
  5. @GET
  6. @Produces(MediaType.APPLICATION_JSON)
  7. @Consumes(MediaType.APPLICATION_JSON)
  8. public Employees getAllEmployees()
  9. {
  10. Employees list = new Employees();
  11. list.setEmployeeList(new ArrayList<Employee>());
  12. list.getEmployeeList().add(new Employee(1, "Lokesh Gupta"));
  13. list.getEmployeeList().add(new Employee(2, "Alex Kolenchiskey"));
  14. list.getEmployeeList().add(new Employee(3, "David Kameron"));
  15. return list;
  16. }
  17. }

4. 测试 Jersey AuthenticationFilter

让我们测试认证设置是否有效。

点击 URL:http://localhost:8080/JerseyDemos/rest/employees

Jersey REST API 安全示例 - 图1

Jersey 认证失败的请求

在基本认证参数中传递用户名和密码:howtodoinjava/password

Jersey REST API 安全示例 - 图2

Jersey 认证成功的请求

单击下面的链接下载 jersey rest api 认证示例应用的源代码。

JerseyDemos

学习愉快!