package dk.kroeger.dennis.shiro.jersey.filters;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.UnauthorizedException;
import org.apache.shiro.subject.Subject;

import javax.ws.rs.ForbiddenException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import java.io.IOException;

/**
 * Common base class for all request filters.
 *
 * @author Dennis Du Krøger
 * @since 02-08-2014
 */
abstract class ShiroContainerRequestFilter implements ContainerRequestFilter {

	/**
	 * @return True if current filter is satisfied.
	 */
	protected abstract boolean checkAccess(Subject subject);

	/**
	 * In most cases, a filter requires the user to be remembered or authenticated,
	 * but some filters may skip that.
	 *
	 * @return True if filter consider user allowed
	 */
	boolean checkAuthentication(Subject subject) {
		return subject.isRemembered() || subject.isAuthenticated();
	}

	@Override
	public void filter(ContainerRequestContext containerRequestContext) throws IOException {
		Subject subject = SecurityUtils.getSubject();
		if (!checkAuthentication(subject)) {
			throw new UnauthorizedException();
		} else if (!checkAccess(subject)) {
			throw new ForbiddenException();
		}
	}

}

@@ -109,117 +109,25 @@
 iro.
-authz.UnauthorizedException;%0Aimport org.apache.shiro.subject.Subject;%0A%0Aimport javax.ws.rs.ForbiddenException;
+subject.Subject;%0A
 %0Aimp
@@ -230,16 +230,50 @@
 Filter;%0A
+import javax.ws.rs.core.Response;%0A
 import j
@@ -1082,26 +1082,110 @@
 )) %7B%0A%09%09%09
-throw new 
+containerRequestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).entity(%0A%09%09%09%09%09%22
 Unauthor
@@ -1188,26 +1188,26 @@
 thorized
-Exception(
+%22).build()
 );%0A%09%09%7D e
@@ -1246,37 +1246,118 @@
 %0A%09%09%09
-throw new ForbiddenException(
+containerRequestContext.abortWith(Response.status(Response.Status.FORBIDDEN).entity(%0A%09%09%09%09%09%22Forbidden%22).build()
 );%0A%09

Use proper Jersey aborts instead of Shiro Exceptions