在此 Jersey rest 安全示例中,我们将学习通过基本认证保护 Jersey REST API 的安全。 这将强制每个用户提供用户名/密码以认证到门户。 另外,用户还必须具有一定级别的角色。 我从为 RESTEasy API 安全性创建的另一个示例扩展了此示例,并使用ContainerRequestFilter实现在用户登陆实际的 REST API 之前验证其访问权限。
Table of Contents1\. Create request authentication filter2\. Register AuthenticationFilter with ResourceConfig3\. Secure REST APIs4\. Test Jersey AuthenticationFilter
1. 创建请求认证过滤器
我们知道 JAX-RS 2.0 具有用于处理请求前和请求的过滤器,因此我们将使用ContainerRequestFilter接口。 在此过滤器中,我们将获取请求尝试访问的方法的详细信息。
我们将找出该方法上所有与安全性相关的配置,并在此过滤器中验证所有内容,例如,注解,例如@PermitAll,@DenyAll或@RolesAllowed。
根据方法上的注解,我们将决定是通过还是阻止请求。
package com.howtodoinjava.jersey.provider;import java.lang.reflect.Method;import java.util.Arrays;import java.util.HashSet;import java.util.List;import java.util.Set;import java.util.StringTokenizer;import javax.annotation.security.DenyAll;import javax.annotation.security.PermitAll;import javax.annotation.security.RolesAllowed;import javax.ws.rs.container.ContainerRequestContext;import javax.ws.rs.container.ResourceInfo;import javax.ws.rs.core.Context;import javax.ws.rs.core.MultivaluedMap;import javax.ws.rs.core.Response;import javax.ws.rs.ext.Provider;import org.glassfish.jersey.internal.util.Base64;/*** This filter verify the access permissions for a user* based on username and passowrd provided in request* */@Providerpublic class AuthenticationFilter implements javax.ws.rs.container.ContainerRequestFilter{@Contextprivate ResourceInfo resourceInfo;private static final String AUTHORIZATION_PROPERTY = "Authorization";private static final String AUTHENTICATION_SCHEME = "Basic";@Overridepublic void filter(ContainerRequestContext requestContext){Method method = resourceInfo.getResourceMethod();//Access allowed for allif( ! method.isAnnotationPresent(PermitAll.class)){//Access denied for allif(method.isAnnotationPresent(DenyAll.class)){requestContext.abortWith(Response.status(Response.Status.FORBIDDEN).entity("Access blocked for all users !!").build(););return;}//Get request headersfinal MultivaluedMap<String, String> headers = requestContext.getHeaders();//Fetch authorization headerfinal List<String> authorization = headers.get(AUTHORIZATION_PROPERTY);//If no authorization information present; block accessif(authorization == null || authorization.isEmpty()){requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).entity("You cannot access this resource").build());return;}//Get encoded username and passwordfinal String encodedUserPassword = authorization.get(0).replaceFirst(AUTHENTICATION_SCHEME + " ", "");//Decode username and passwordString usernameAndPassword = new String(Base64.decode(encodedUserPassword.getBytes()));;//Split username and password tokensfinal StringTokenizer tokenizer = new StringTokenizer(usernameAndPassword, ":");final String username = tokenizer.nextToken();final String password = tokenizer.nextToken();//Verifying Username and passwordSystem.out.println(username);System.out.println(password);//Verify user accessif(method.isAnnotationPresent(RolesAllowed.class)){RolesAllowed rolesAnnotation = method.getAnnotation(RolesAllowed.class);Set<String> rolesSet = new HashSet<String>(Arrays.asList(rolesAnnotation.value()));//Is user valid?if( ! isUserAllowed(username, password, rolesSet)){requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).entity("You cannot access this resource").build(););return;}}}}private boolean isUserAllowed(final String username, final String password, final Set<String> rolesSet){boolean isAllowed = false;//Step 1\. Fetch password from database and match with password in argument//If both match then get the defined role for user from database and continue; else return isAllowed [false]//Access the database and do this part yourself//String userRole = userMgr.getUserRole(username);if(username.equals("howtodoinjava") && password.equals("password")){String userRole = "ADMIN";//Step 2\. Verify user roleif(rolesSet.contains(userRole)){isAllowed = true;}}return isAllowed;}}
2. 向ResourceConfig注册AuthenticationFilter
现在,您需要在ResourceConfig实例上方注册过滤器。 因此,创建一个如下所示的实例:
package com.howtodoinjava.jersey;import org.glassfish.jersey.filter.LoggingFilter;import org.glassfish.jersey.server.ResourceConfig;import com.howtodoinjava.jersey.provider.AuthenticationFilter;import com.howtodoinjava.jersey.provider.GsonMessageBodyHandler;public class CustomApplication extends ResourceConfig{public CustomApplication(){packages("com.howtodoinjava.jersey");register(LoggingFilter.class);register(GsonMessageBodyHandler.class);//Register Auth Filter hereregister(AuthenticationFilter.class);}}
并将此资源配置添加到web.xml文件中。
<!DOCTYPE web-app PUBLIC"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN""http://java.sun.com/dtd/web-app_2_3.dtd" ><web-app><display-name>Archetype Created Web Application</display-name><servlet><servlet-name>jersey-serlvet</servlet-name><servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class><init-param><param-name>javax.ws.rs.Application</param-name><param-value>com.howtodoinjava.jersey.CustomApplication</param-value></init-param><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>jersey-serlvet</servlet-name><url-pattern>/rest/*</url-pattern></servlet-mapping></web-app>
3. 安全的 REST API
现在是时候保护 REST API 了。 如下使用标准的 JAX-RS 注解。
@Path("/employees")public class JerseyService{@RolesAllowed("ADMIN")@GET@Produces(MediaType.APPLICATION_JSON)@Consumes(MediaType.APPLICATION_JSON)public Employees getAllEmployees(){Employees list = new Employees();list.setEmployeeList(new ArrayList<Employee>());list.getEmployeeList().add(new Employee(1, "Lokesh Gupta"));list.getEmployeeList().add(new Employee(2, "Alex Kolenchiskey"));list.getEmployeeList().add(new Employee(3, "David Kameron"));return list;}}
4. 测试 Jersey AuthenticationFilter
让我们测试认证设置是否有效。
点击 URL:http://localhost:8080/JerseyDemos/rest/employees

Jersey 认证失败的请求
在基本认证参数中传递用户名和密码:howtodoinjava/password

Jersey 认证成功的请求
单击下面的链接下载 jersey rest api 认证示例应用的源代码。
学习愉快!
