Java 如何设置Spring安全性以允许来自特定应用程序的REST调用?
Spring启动应用程序使用Spring Security保护其API元素不受未经授权的用户的攻击。但该应用程序具有公共url模式,需要从未经身份验证的用户处调用,只要这些用户来自某些应用程序需要对下面的代码进行哪些特定更改,以便从特定呼叫位置从未经身份验证的用户成功调用Java 如何设置Spring安全性以允许来自特定应用程序的REST调用?,java,spring,spring-security,spring-boot,Java,Spring,Spring Security,Spring Boot,Spring启动应用程序使用Spring Security保护其API元素不受未经授权的用户的攻击。但该应用程序具有公共url模式,需要从未经身份验证的用户处调用,只要这些用户来自某些应用程序需要对下面的代码进行哪些特定更改,以便从特定呼叫位置从未经身份验证的用户成功调用/some test service端点? 例如,我知道终端命令是从运行Spring Boot应用程序的同一台本地主机上运行的。我还知道前端AngularJS/Node.js调用应用程序正在特定端口上运行,如端口9000 下面是
/some test service
端点?
例如,我知道终端命令是从运行Spring Boot应用程序的同一台本地主机上运行的。我还知道前端AngularJS/Node.js调用应用程序正在特定端口上运行,如端口9000
下面是我在运行Spring Boot应用程序的devbox中从CentOS终端键入以下POST
测试时发生的情况:
[user@localhost controllers]$ curl -i -X POST -H "Content-Type:application/json" -d '{ "wleadid" : "1" }' http://localhost:8001/some-test-service
HTTP/1.1 403 Forbidden
Server: Apache-Coyote/1.1
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Set-Cookie: JSESSIONID=530A75F962CCFB95EEDF43051BC71573; Path=/; HttpOnly
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Wed, 06 Apr 2016 09:11:09 GMT
{"timestamp":1459933869769,"status":403,"error":"Forbidden","message":"Expected CSRF token not found. Has your session expired?","path":"/some-test-service"}
[user@localhost controllers]$
@SpringBootApplication
@Controller
@EnableJpaRepositories(basePackages = "demo", considerNestedRepositories = true)
public class UiApplication extends WebMvcConfigurerAdapter {
@Autowired
private Users users;
public static void main(String[] args) {
SpringApplication.run(UiApplication.class, args);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public LocaleResolver localeResolver() {
SessionLocaleResolver slr = new SessionLocaleResolver();
slr.setDefaultLocale(Locale.US);
return slr;
}
@Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
LocaleChangeInterceptor lci = new LocaleChangeInterceptor();
lci.setParamName("lang");
return lci;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeChangeInterceptor());
}
@Order(Ordered.HIGHEST_PRECEDENCE)
@Configuration
protected static class AuthenticationSecurity extends GlobalAuthenticationConfigurerAdapter {
@Autowired
private Users users;
@Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(users);
}
}
@SuppressWarnings("deprecation")
@Configuration
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
@EnableWebMvcSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
protected static class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin()
.successHandler(new MyAuthenticationSuccessHandler())
.and()
.httpBasic().and()
.authorizeRequests()
.antMatchers("/some-test-service").permitAll()
.antMatchers("/", "/url1", "/url2", "/url3*", "/url4*", "/url5*").permitAll()
.anyRequest().authenticated()
.and()
.csrf()
.csrfTokenRepository(csrfTokenRepository())
.and()
.addFilterAfter(csrfHeaderFilter(), CsrfFilter.class);
}
private Filter csrfHeaderFilter() {
return new OncePerRequestFilter() {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
System.out.println("----- INSIDE new OncePerRequestFilter().doFilterInternal(...) ");
CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
if (csrf != null) {
Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
String token = csrf.getToken();
if (cookie == null || token != null && !token.equals(cookie.getValue())) {
cookie = new Cookie("XSRF-TOKEN", token);
cookie.setPath("/");
response.addCookie(cookie);
}
}
filterChain.doFilter(request, response);
System.out.println("csrf.getToken() is: "+csrf.getToken());
}
};
}
private CsrfTokenRepository csrfTokenRepository() {
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
repository.setHeaderName("X-XSRF-TOKEN");
System.out.println("repository.toString() is: "+repository.toString());
return repository;
}
}
@Repository
interface UserRepository extends CrudRepository<User, Long> {
User findByName(String name);
}
}
这是Spring安全配置,位于完整的UiApplication.java
中,它是Spring Boot应用程序的主要类:
[user@localhost controllers]$ curl -i -X POST -H "Content-Type:application/json" -d '{ "wleadid" : "1" }' http://localhost:8001/some-test-service
HTTP/1.1 403 Forbidden
Server: Apache-Coyote/1.1
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Set-Cookie: JSESSIONID=530A75F962CCFB95EEDF43051BC71573; Path=/; HttpOnly
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Wed, 06 Apr 2016 09:11:09 GMT
{"timestamp":1459933869769,"status":403,"error":"Forbidden","message":"Expected CSRF token not found. Has your session expired?","path":"/some-test-service"}
[user@localhost controllers]$
@SpringBootApplication
@Controller
@EnableJpaRepositories(basePackages = "demo", considerNestedRepositories = true)
public class UiApplication extends WebMvcConfigurerAdapter {
@Autowired
private Users users;
public static void main(String[] args) {
SpringApplication.run(UiApplication.class, args);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public LocaleResolver localeResolver() {
SessionLocaleResolver slr = new SessionLocaleResolver();
slr.setDefaultLocale(Locale.US);
return slr;
}
@Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
LocaleChangeInterceptor lci = new LocaleChangeInterceptor();
lci.setParamName("lang");
return lci;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeChangeInterceptor());
}
@Order(Ordered.HIGHEST_PRECEDENCE)
@Configuration
protected static class AuthenticationSecurity extends GlobalAuthenticationConfigurerAdapter {
@Autowired
private Users users;
@Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(users);
}
}
@SuppressWarnings("deprecation")
@Configuration
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
@EnableWebMvcSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
protected static class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin()
.successHandler(new MyAuthenticationSuccessHandler())
.and()
.httpBasic().and()
.authorizeRequests()
.antMatchers("/some-test-service").permitAll()
.antMatchers("/", "/url1", "/url2", "/url3*", "/url4*", "/url5*").permitAll()
.anyRequest().authenticated()
.and()
.csrf()
.csrfTokenRepository(csrfTokenRepository())
.and()
.addFilterAfter(csrfHeaderFilter(), CsrfFilter.class);
}
private Filter csrfHeaderFilter() {
return new OncePerRequestFilter() {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
System.out.println("----- INSIDE new OncePerRequestFilter().doFilterInternal(...) ");
CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
if (csrf != null) {
Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
String token = csrf.getToken();
if (cookie == null || token != null && !token.equals(cookie.getValue())) {
cookie = new Cookie("XSRF-TOKEN", token);
cookie.setPath("/");
response.addCookie(cookie);
}
}
filterChain.doFilter(request, response);
System.out.println("csrf.getToken() is: "+csrf.getToken());
}
};
}
private CsrfTokenRepository csrfTokenRepository() {
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
repository.setHeaderName("X-XSRF-TOKEN");
System.out.println("repository.toString() is: "+repository.toString());
return repository;
}
}
@Repository
interface UserRepository extends CrudRepository<User, Long> {
User findByName(String name);
}
}
@springboot应用程序
@控制器
@EnableJpaRepositories(basePackages=“demo”,considerNestedRepositories=true)
公共类UiApplication扩展WebMVCConfigureAdapter{
@自动连线
私人用户;
公共静态void main(字符串[]args){
run(UiApplication.class,args);
}
@豆子
公共密码编码器PasswordEncoder(){
返回新的BCryptPasswordEncoder();
}
@豆子
公共LocaleResolver LocaleResolver(){
SessionLocaleResolver slr=新SessionLocaleResolver();
slr.setDefaultLocale(Locale.US);
返回单反;
}
@豆子
公共LocaleChangeInterceptor LocaleChangeInterceptor(){
LocaleChangeInterceptor lci=新的LocaleChangeInterceptor();
lci.setParamName(“lang”);
返回lci;
}
@凌驾
公共无效附加接收器(侦听器注册表){
addInterceptor(localeChangeInterceptor());
}
@顺序(有序。最高优先级)
@配置
受保护的静态类身份验证安全性扩展了GlobalAuthenticationConfigurerAdapter{
@自动连线
私人用户;
@凌驾
public void init(AuthenticationManagerBuilder auth)引发异常{
auth.userDetailsService(用户);
}
}
@抑制警告(“弃用”)
@配置
@顺序(SecurityProperty.ACCESS\u OVERRIDE\u顺序)
@启用WebMVC安全性
@EnableGlobalMethodSecurity(Prespenabled=true)
受保护的静态类SecurityConfiguration扩展了WebSecurity配置适配器{
@凌驾
受保护的无效配置(HttpSecurity http)引发异常{
http
.formLogin()
.successHandler(新的MyAuthenticationSuccessHandler())
.及()
.httpBasic()和()
.授权请求()
.antMatchers(“/some test service”).permitAll()
.antMatchers(“/”、“/url1”、“/url2”、“/url3*”、“/url4*”、“/url5*”).permitAll()
.anyRequest().authenticated()
.及()
.csrf()
.csrfTokenRepository(csrfTokenRepository())
.及()
.addFilterAfter(csrfHeaderFilter(),CsrfFilter.class);
}
专用筛选器csrfHeaderFilter(){
返回新的OncePerRequestFilter(){
@凌驾
受保护的void doFilterInternal(HttpServletRequest请求、HttpServletResponse响应、FilterChain FilterChain)
抛出ServletException、IOException{
System.out.println(“----在新的OncePerRequestFilter()内部。doFilterInternal(…)”;
CsrfToken csrf=(CsrfToken)request.getAttribute(CsrfToken.class.getName());
如果(csrf!=null){
cookiecookie=WebUtils.getCookie(请求,“XSRF-TOKEN”);
字符串标记=csrf.getToken();
如果(cookie==null | | token!=null&&!token.equals(cookie.getValue())){
cookie=新cookie(“XSRF-TOKEN”,TOKEN);
cookie.setPath(“/”);
addCookie(cookie);
}
}
filterChain.doFilter(请求、响应);
println(“csrf.getToken()是:”+csrf.getToken());
}
};
}
私有CsrfTokenRepository CsrfTokenRepository(){
httpsessionsrftokenrepository=新的httpsessionsrftokenrepository();
setHeaderName(“X-XSRF-TOKEN”);
System.out.println(“repository.toString()是:”+repository.toString());
返回存储库;
}
}
@存储库
接口UserRepository扩展了Crudepository{
用户findByName(字符串名称);
}
}
我也有类似的问题。但是我的配置在没有csrf的情况下工作。
公共访问链接:“localhost:8080/someTestUrl/”,但其他引用需要授权
我的看法是:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
MongoDBAuthenticationProviderService authenticationProvider;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http
.anonymous()
.and()
.authorizeRequests().antMatchers("/someTestUrl").permitAll()
.and()
.formLogin().permitAll().loginPage("/login").usernameParameter("username").passwordParameter("password")
.and()
.logout().permitAll()
.and()
.authorizeRequests().anyRequest().fullyAuthenticated()
.and()
.httpBasic().disable()
.exceptionHandling().accessDeniedPage("/403")
.and()
.headers()
.contentTypeOptions()
.disable();
}
}
和资源配置:
@EnableResourceServer
@Configuration
public class ResourseConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http
.anonymous()
.and()
.authorizeRequests().antMatchers("/someTestUrl/**").permitAll()
.and()
.formLogin().permitAll().loginPage("/login").usernameParameter("username").passwordParameter("password")
.and()
.logout().permitAll()
.and()
.authorizeRequests().anyRequest().fullyAuthenticated()
.and()
.httpBasic().disable()
.exceptionHandling().accessDeniedPage("/403")
.and()
.headers().contentTypeOptions()
.disable();
}
}
也许它会对你有所帮助。我也有类似的问题。但是我的配置在没有csrf的情况下工作。 公共访问链接:“localhost:8080/someTestUrl/”,但其他引用需要授权 我的看法是:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
MongoDBAuthenticationProviderService authenticationProvider;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http
.anonymous()
.and()
.authorizeRequests().antMatchers("/someTestUrl").permitAll()
.and()
.formLogin().permitAll().loginPage("/login").usernameParameter("username").passwordParameter("password")
.and()
.logout().permitAll()
.and()
.authorizeRequests().anyRequest().fullyAuthenticated()
.and()
.httpBasic().disable()
.exceptionHandling().accessDeniedPage("/403")
.and()
.headers()
.contentTypeOptions()
.disable();
}
}
和资源配置:
@EnableResourceServer
@Configuration
public class ResourseConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http
.anonymous()
.and()
.authorizeRequests().antMatchers("/someTestUrl/**").permitAll()
.and()
.formLogin().permitAll().loginPage("/login").usernameParameter("username").passwordParameter("password")
.and()
.logout().permitAll()
.and()
.authorizeRequests().anyRequest().fullyAuthenticated()
.and()
.httpBasic().disable()
.exceptionHandling().accessDeniedPage("/403")
.and()
.headers().contentTypeOptions()
.disable();
}
}
也许这会对你有所帮助。你可以关注这个帖子@kimdung谢谢。请留下您的评论,以便其他人也可以阅读。但请注意,MDienum在另一篇文章中的回答在
SecurityConfig
中使用了WebSecurity
对象,而本篇文章中的版本使用了HttpSecurity
。此外,当前OP中的错误消息指定了XSRF证书