在此Jersey rest 安全示例中,我们将学习使用基本身份验证保护Jersey REST API。这将强制每个用户提供用户名/密码以对门户进行身份验证。此外,用户还必须具有一定级别的角色。我从为 RESTEasy API 安全性 创建的其他示例扩展了这个示例,并使用了 ContainerRequestFilter 实现在用户登陆实际 REST API 之前验证用户的访问权限。
我们知道 JAX-RS 2.0 具有用于前后请求处理的过滤器,因此我们将使用 ContainerRequestFilter
接口。在此过滤器中,我们将获取请求尝试访问的方法的详细信息。
我们将找出该方法的所有安全相关配置,并验证此过滤器中的所有内容,例如注释如 @PermitAll
、@DenyAll
或 @RolesAllowed
。
根据应用在方法上的注释,我们将决定通过或阻止请求。
package com.cundage.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 * */ @Provider public class AuthenticationFilter implements javax.ws.rs.container.ContainerRequestFilter { @Context private ResourceInfo resourceInfo; private static final String AUTHORIZATION_PROPERTY = "Authorization"; private static final String AUTHENTICATION_SCHEME = "Basic"; @Override public void filter(ContainerRequestContext requestContext) { Method method = resourceInfo.getResourceMethod(); //Access allowed for all if( ! method.isAnnotationPresent(PermitAll.class)) { //Access denied for all if(method.isAnnotationPresent(DenyAll.class)) { requestContext.abortWith(Response.status(Response.Status.FORBIDDEN) .entity("Access blocked for all users !!").build();); return; } //Get request headers final MultivaluedMap<String, String> headers = requestContext.getHeaders(); //Fetch authorization header final List<String> authorization = headers.get(AUTHORIZATION_PROPERTY); //If no authorization information present; block access if(authorization == null || authorization.isEmpty()) { requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED) .entity("You cannot access this resource").build()); return; } //Get encoded username and password final String encodedUserPassword = authorization.get(0).replaceFirst(AUTHENTICATION_SCHEME + " ", ""); //Decode username and password String usernameAndPassword = new String(Base64.decode(encodedUserPassword.getBytes()));; //Split username and password tokens final StringTokenizer tokenizer = new StringTokenizer(usernameAndPassword, ":"); final String username = tokenizer.nextToken(); final String password = tokenizer.nextToken(); //Verifying Username and password System.out.println(username); System.out.println(password); //Verify user access if(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("cundage") && password.equals("password")) { String userRole = "ADMIN"; //Step 2. Verify user role if(rolesSet.contains(userRole)) { isAllowed = true; } } return isAllowed; } }
现在您需要使用 ResourceConfig
实例注册上述过滤器。所以创建一个如下所示的实例:
package com.cundage.jersey; import org.glassfish.jersey.filter.LoggingFilter; import org.glassfish.jersey.server.ResourceConfig; import com.cundage.jersey.provider.AuthenticationFilter; import com.cundage.jersey.provider.GsonMessageBodyHandler; public class CustomApplication extends ResourceConfig { public CustomApplication() { packages("com.cundage.jersey"); register(LoggingFilter.class); register(GsonMessageBodyHandler.class); //Register Auth Filter here register(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.cundage.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>
现在是保护 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; } }
让我们测试身份验证设置是否有效。
单击下面的链接下载jersey rest api 身份验证示例 应用程序的源代码。
快乐学习!!
地址:https://www.cundage.com/article/jersey-rest-security.html