嵌入式Jetty和Apache CXF:借助Spring Security来保护REST服务

最近,我遇到了一个非常有趣的问题,我认为这只花了我几分钟就解决了:在Windows Server 2003中使用Spring Security (当前稳定版本3.2.5 )保护Apache CXF (当前版本3.0.1 )/ JAX-RS REST服务。在嵌入式Jetty容器(当前版本9.2 )中运行的应用程序。 最后,一旦您了解了事物如何协同工作并了解了细微的内在细节,这将变得非常容易。 这篇博客文章将试图揭示这一点。

我们的示例应用程序将公开一个简单的JAX-RS / REST服务来管理人员。 但是,我们不希望所有人都这样做,因此需要HTTP基本身份验证才能访问部署在http:// localhost:8080 / api / rest / people的端点。 让我们看一下PeopleRestService类:

package com.example.rs;import javax.json.Json;
import javax.json.JsonArray;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;@Path( "/people" ) 
public class PeopleRestService {@Produces( { "application/json" } )@GETpublic JsonArray getPeople() {return Json.createArrayBuilder().add( Json.createObjectBuilder().add( "firstName", "Tom" ).add( "lastName", "Tommyknocker" ).add( "email", "a@b.com" ) ).build();}
}

正如您在上面的代码片段中所看到的,没有任何迹象表明该REST服务是安全的,只是几个熟悉的JAX-RS批注。

现在,让我们根据出色的Spring Security文档声明所需的安全配置。 有很多方法可以配置Spring Security,但是我们将展示其中两种:使用内存内身份验证和使用用户详细信息服务,这两种方法都基于WebSecurityConfigurerAdapter构建 。 让我们从内存中身份验证开始,因为它是最简单的一种:

package com.example.config;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity( securedEnabled = true )
public class InMemorySecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredpublic void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {auth.inMemoryAuthentication().withUser( "user" ).password( "password" ).roles( "USER" ).and().withUser( "admin" ).password( "password" ).roles( "USER", "ADMIN" );}@Overrideprotected void configure( HttpSecurity http ) throws Exception {http.httpBasic().and().sessionManagement().sessionCreationPolicy( SessionCreationPolicy.STATELESS ).and().authorizeRequests().antMatchers("/**").hasRole( "USER" );}
}

在上面有该段两个用户定义: 用户与角色用户管理员用户的角色,ADMIN。 我们还通过将授权策略设置为仅允许访问角色为USER的用户来保护所有URL( / ** )。 作为应用程序配置的一部分,让我们使用@Import批注将其插入AppConfig类。

package com.example.config;import java.util.Arrays;import javax.ws.rs.ext.RuntimeDelegate;import org.apache.cxf.bus.spring.SpringBus;
import org.apache.cxf.endpoint.Server;
import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
import org.apache.cxf.jaxrs.provider.jsrjsonp.JsrJsonpProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Import;import com.example.rs.JaxRsApiApplication;
import com.example.rs.PeopleRestService;@Configuration
@Import( InMemorySecurityConfig.class )
public class AppConfig { @Bean( destroyMethod = "shutdown" )public SpringBus cxf() {return new SpringBus();}@Bean @DependsOn ( "cxf" )public Server jaxRsServer() {JAXRSServerFactoryBean factory = RuntimeDelegate.getInstance().createEndpoint( jaxRsApiApplication(), JAXRSServerFactoryBean.class );factory.setServiceBeans( Arrays.< Object >asList( peopleRestService() ) );factory.setAddress( factory.getAddress() );factory.setProviders( Arrays.< Object >asList( new JsrJsonpProvider() ) );return factory.create();}@Bean public JaxRsApiApplication jaxRsApiApplication() {return new JaxRsApiApplication();}@Bean public PeopleRestService peopleRestService() {return new PeopleRestService();}  
}

到目前为止,除了最有趣的部分,我们还有所有其他部分:运行嵌入式Jetty实例并创建正确的servlet映射,侦听器,传递我们创建的配置的代码。

package com.example;import java.util.EnumSet;import javax.servlet.DispatcherType;import org.apache.cxf.transport.servlet.CXFServlet;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.filter.DelegatingFilterProxy;import com.example.config.AppConfig;public class Starter {public static void main( final String[] args ) throws Exception {Server server = new Server( 8080 );// Register and map the dispatcher servletfinal ServletHolder servletHolder = new ServletHolder( new CXFServlet() );final ServletContextHandler context = new ServletContextHandler();   context.setContextPath( "/" );context.addServlet( servletHolder, "/rest/*" );  context.addEventListener( new ContextLoaderListener() );context.setInitParameter( "contextClass", AnnotationConfigWebApplicationContext.class.getName() );context.setInitParameter( "contextConfigLocation", AppConfig.class.getName() );// Add Spring Security Filter by the namecontext.addFilter(new FilterHolder( new DelegatingFilterProxy( "springSecurityFilterChain" ) ), "/*", EnumSet.allOf( DispatcherType.class ));server.setHandler( context );server.start();server.join(); }
}

除了过滤器部分,大多数代码不需要任何说明。 这就是我所说的微妙的固有细节: DelegatingFilterProxy应该配置为过滤器名称,该名称必须完全是springSecurityFilterChain ,因为Spring Security会为其命名。 这样,我们配置的安全规则将适用于任何JAX-RS服务调用(安全过滤器在Apache CXF servlet之前执行),需要完全认证。 让我们通过构建和运行项目来快速检查:

mvn clean package   
java -jar target/jax-rs-2.0-spring-security-0.0.1-SNAPSHOT.jar

在不提供用户名和密码的情况下发出HTTP GET调用不会成功,并返回HTTP 状态代码401 。

> curl -i http://localhost:8080/rest/api/peopleHTTP/1.1 401 Full authentication is required to access this resource
WWW-Authenticate: Basic realm="Realm"
Cache-Control: must-revalidate,no-cache,no-store
Content-Type: text/html; charset=ISO-8859-1
Content-Length: 339
Server: Jetty(9.2.2.v20140723)

提供的用户名和密码相同的HTTP GET调用返回成功的响应(服务器生成一些JSON)。

> curl -i -u user:password http://localhost:8080/rest/api/peopleHTTP/1.1 200 OK
Date: Sun, 28 Sep 2014 20:07:35 GMT
Content-Type: application/json
Content-Length: 65
Server: Jetty(9.2.2.v20140723)[{"firstName":"Tom","lastName":"Tommyknocker","email":"a@b.com"}]

太好了,它就像一个魅力! 事实证明,这确实非常容易。 同样,如前所述,可以使用用户详细信息服务代替内存中身份验证,这是一个示例,该示例说明了如何进行:

package com.example.config;import java.util.Arrays;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
public class UserDetailsSecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredpublic void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService( userDetailsService() );}@Beanpublic UserDetailsService userDetailsService() {return new UserDetailsService() {@Overridepublic UserDetails loadUserByUsername( final String username ) throws UsernameNotFoundException {if( username.equals( "admin" ) ) {return new User( username, "password", true, true, true, true,Arrays.asList(new SimpleGrantedAuthority( "ROLE_USER" ),new SimpleGrantedAuthority( "ROLE_ADMIN" )));} else if ( username.equals( "user" ) ) {return new User( username, "password", true, true, true, true,Arrays.asList(new SimpleGrantedAuthority( "ROLE_USER" )));} return null;}};}@Overrideprotected void configure( HttpSecurity http ) throws Exception {http.httpBasic().and().sessionManagement().sessionCreationPolicy( SessionCreationPolicy.STATELESS ).and().authorizeRequests().antMatchers("/**").hasRole( "USER" );}
}

AppConfig类中的@Import(InMemorySecurityConfig.class)替换为@Import( UserDetailsS​​ecurityConfig.class)会得到相同的结果,因为两个安全配置都定义了相同的用户及其角色集。

我希望,此博客文章可以节省您一些时间,并为您提供一个良好的起点,因为Apache CXF和Spring Security在Jetty的保护下相处得很好!

  • 完整的源代码可在GitHub上获得 。

翻译自: https://www.javacodegeeks.com/2014/09/embedded-jetty-and-apache-cxf-secure-rest-services-with-spring-security.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/362080.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

我所知道的前端组件化与模块化

序言&#xff1a;组件化&#xff1f;模块化&#xff1f;这都是什么鬼&#xff1f;这是最初看到这2个新名词的反应。随着时间的推移&#xff0c;似乎、可能、大概明白了一点&#xff0c;于是想说说自己的理解(仅仅是自己的理解) 一、组件化 忘记什么时候看到这个词的了&#x…

关于通过反汇编查看dll的方法【转】(

关于通过反汇编查看dll的方法【转】( http://blog.sina.com.cn/s/blog_51a3c0380100f9md.html 今天想看一个dll的内容&#xff0c;苦于没有相关工具&#xff0c;从csdn上找到有这么段文字&#xff0c;收益匪浅啊&#xff0c;收藏&#xff01; 可以通过反汇编来知道接口函数的参…

openocd安装与调试

环境&#xff1a; 硬件&#xff1a;PC机<------>ARM仿真器v8.00<------>已下载好bit流的Xinlinx SoC开发板&#xff08;其上有arm cortex-a9核&#xff09; 软件&#xff1a;Redhat Linux6&#xff08;或虚拟机&#xff09; openocd 使用openocd下载程序&#xff…

在React中获取数据

React初学者经常从不需要获取数据的应用开始。他们经常面临一个计数器&#xff0c;任务列表获取井字棋游戏应用。这是很好的&#xff0c;因为在开始学习React的时候&#xff0c;数据获取在你的应用中添加了另一层复杂度。 然而&#xff0c;有些时候你想要从自己的或者第三方AP…

使用Project Lombok减少Java应用程序中的样板代码

对Java编程语言最常提出的批评之一是它需要大量的样板代码 。 对于简单的类尤其如此&#xff0c;该类只需要存储一些值就可以。 您需要这些值的getter和setter&#xff0c;也许您还需要一个构造函数&#xff0c;覆盖equals&#xff08;&#xff09;和 hashcode&#xff08;&am…

DOM之城市二级联动

1、HTML内容 <select id"province"><option>请选择</option><option>山东省</option><option>吉林省</option><option>上海市</option></select><select id"city"><option>请选择…

跳转指令-JMP

page 60,132TITLE A0405Jump(EXE) JMP跳转指令.MODEL SMALL.STACK 64.DATAORG 100H ;规定程序的起始地址A10MAIN PROC NEARMOV AX,00MOV BX,00MOV CX,1A20: ADD AX,01ADD BX,AXSHL CX,1 ;左移一位JMP A20 ;跳转到A20A10MAIN endp jmp格式 [label:] jmp short/near/far/address…

java输出毫秒时间

SimpleDateFormat df new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");// 输出字符串System.out.println(df.format(new Date()));转载于:https://www.cnblogs.com/longchang/p/11139947.html

Three.js制作360度全景图

这是个基于three.js的插件&#xff0c;预览地址&#xff1a;戳这里 使用方法&#xff1a; 1、这个插件的用法很简单&#xff0c;引入如下2个js <script src"js/three.min.js"></script><script src"js/photo-sphere-viewer.min.js">&l…

C++资源库不完全版本

http://www.360doc.com/content/10/0414/20/59141_23072568.shtml boost graph...转载于:https://www.cnblogs.com/seon/archive/2011/08/08/2131246.html

babel6和babel7中关于polyfill和preset-env和babel-plugin-transform-runtime等总结

记录自己零散的收获&#xff0c;随笔。 一些基础 babel的作用是转换JS新的特性代码为大部分浏览器能运行的代码。 babel转码又分为两部分&#xff0c;一个是语法转换&#xff0c;一个是API转换。 对于API的转换又分为两部分&#xff0c;一个是全局API例如Promise&#xff0c…

十六、CI框架之数据库操作get用法

一、使用数据库的Get方法读取内容&#xff0c;如下代码&#xff1a; 二、数据库如下&#xff1a; 二、效果如下&#xff1a; 转载于:https://www.cnblogs.com/tianpan2019/p/11141809.html

使用Spring Boot和Spring MVC自定义HttpMessageConverters

为Spring Boot应用程序或直接的Spring MVC应用程序公开基于REST的终结点很简单&#xff0c;以下是一个控制器&#xff0c;该终结点公开了一个终结点&#xff0c;用于基于其发布的内容创建实体&#xff1a; RestController RequestMapping("/rest/hotels") public cl…

JS如何禁止别人查看网站源码

四种查看路径&#xff1a; 查看效果&#xff1a;猛戳 1、直接按F12 2、Ctrl Shift I查看 3、鼠标点击右键查看 4、Ctrl uview-source: url 把以上三种状态都屏蔽掉就可以了&#xff0c;document有onkeydown(键盘按键事件)&#xff0c;该事件里面找到对应的keycode并处理就…

JS相关知识总结(一)

总结下这段时间吸收的许多小知识&#xff0c;以备忘记后翻阅。 关于面向对象 面向对象特征&#xff1a; 具有唯一标识性具有状态具有行为 JS的面向对象和JAVA的实现思路不一样&#xff0c;JS是基于原型并非基于类。但是JS为了看起来更像JAVA&#xff0c;为此添加了一些特性…

WCF系列(二) -- 使用配置文件构建和使用WCF服务

当然&#xff0c;配置一个ServiceHost除了上面说的完全使用代码的方式&#xff0c;更好的方式是使用配置文件&#xff0c;把一些可能需要修改的属性跟代码分离&#xff0c;放到配置文件中&#xff0c;这样可以提供服务配置的灵活性&#xff0c;也更容易维护。 看看前面那个不用…

java读取文件方法

一、多种方式读文件内容。1、按字节读取文件内容2、按字符读取文件内容3、按行读取文件内容4、随机读取文件内容 Java代码 import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileReader; import java.io.IOExcept…

如何使用github搭建个人博客

1、去github官网注册个人帐号&#xff1a;没有的&#xff1a;猛戳这里去注册&#xff0c;比如我的账户名&#xff1a;wjf444128852&#xff0c;我的已经汉化(可在github里搜索github如何汉化有插件) 2、点击仓库-新建&#xff0c;仓库名字必须是&#xff1a;你的github帐号.git…

Spring Boot和Spring Data REST –通过REST公开存储库

使用Spring Boot和Spring Data REST&#xff0c;通过REST公开Spring Data存储库非常容易。 使用最少的代码&#xff0c;您可以创建遵循HATEOAS原理的JPA实体的REST表示。 我决定重用Spring PetClinic的JPA实体&#xff08;业务层&#xff09;作为本文的基础。 应用基础 PetCli…

记录一次cookie导致登录失败的惨案

现象描述&#xff1a; 前端登录成功后并没有从后端那里拿到登录信息&#xff0c;换句话说登录服务告诉我们登录成功了&#xff0c;但是后端却说我们没有登录成功。 背景&#xff1a; 因为前后端分离&#xff0c;所以前后端项目部署在两个子域名下。 因为要打通登录态&#…