Spring Boot 端点未经过身份验证
Posted
技术标签:
【中文标题】Spring Boot 端点未经过身份验证【英文标题】:Spring boot endpoint is not authenticated 【发布时间】:2019-02-10 04:20:58 【问题描述】:我正在努力学习 oauth2
和 jwt
所以我的参考链接是
https://www.devglan.com/spring-security/spring-boot-oauth2-jwt-example
我正在使用spring boot 1.5.15
AuthorizationServerConfig
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter
static final String CLIEN_ID = "devglan-client";
static final String CLIENT_SECRET = "devglan-secret";
static final String GRANT_TYPE_PASSWORD = "password";
static final String AUTHORIZATION_CODE = "authorization_code";
static final String REFRESH_TOKEN = "refresh_token";
static final String IMPLICIT = "implicit";
static final String SCOPE_READ = "read";
static final String SCOPE_WRITE = "write";
static final String TRUST = "trust";
static final int ACCESS_TOKEN_VALIDITY_SECONDS = 1*60;
static final int FREFRESH_TOKEN_VALIDITY_SECONDS = 6*60*60;
@Autowired
private AuthenticationManager authenticationManager;
@Bean
public JwtAccessTokenConverter accessTokenConverter()
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey("as466gf");
return converter;
@Bean
public TokenStore tokenStore()
return new JwtTokenStore(accessTokenConverter());
@Override
public void configure(ClientDetailsServiceConfigurer configurer) throws Exception
configurer
.inMemory()
.withClient(CLIEN_ID)
.secret(CLIENT_SECRET)
.authorizedGrantTypes(GRANT_TYPE_PASSWORD, AUTHORIZATION_CODE, REFRESH_TOKEN, IMPLICIT )
.scopes(SCOPE_READ, SCOPE_WRITE, TRUST)
.accessTokenValiditySeconds(ACCESS_TOKEN_VALIDITY_SECONDS).
refreshTokenValiditySeconds(FREFRESH_TOKEN_VALIDITY_SECONDS);
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception
endpoints.tokenStore(tokenStore())
.authenticationManager(authenticationManager)
.accessTokenConverter(accessTokenConverter());
资源服务器配置
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter
private static final String RESOURCE_ID = "resource_id";
@Override
public void configure(ResourceServerSecurityConfigurer resources)
resources.resourceId(RESOURCE_ID).stateless(false);
@Override
public void configure(HttpSecurity http) throws Exception
http.
anonymous().disable()
.authorizeRequests()
.antMatchers("/users").access("hasRole('SCT_USER')")
.and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter
@Autowired
private SecurityHandler securityHandler;
@Autowired
private UserSecurityService userSecurityService;
private static final String[] PUBLIC_MATCHERS =
"/css/**",
"/js/**",
"/images/**",
"/",
"**/",
"/newUser",
"/forgetPassword",
"/login",
"**/uploads/**",
"/assets/**",
"/api/updateCardStatus",
"/fonts/**",
"/users"
;
/* @Override
protected void configure(HttpSecurity http) throws Exception
http
.authorizeRequests()
*//* antMatchers("/**").*//*
.antMatchers(PUBLIC_MATCHERS).
permitAll().anyRequest().authenticated();
http
.authorizeRequests()
.antMatchers("/admin").hasAnyRole("ROLE_ADMIN").and()
.formLogin().loginPage("/login").permitAll().failureUrl("/login?error")
.successHandler(securityHandler)
.and()
.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/?logout").deleteCookies("remember-me").permitAll()
.and()
.rememberMe();
*/
@Override
protected void configure(HttpSecurity http) throws Exception
http
.csrf().disable()
.anonymous().disable()
.authorizeRequests()
.antMatchers("/api-docs/**").permitAll();
@Override
public void configure(WebSecurity web) throws Exception
web.ignoring()
.antMatchers("/api/updateCardStatus","*/uploads/***","/api/getUsersDetail","/api/getStudentDetails","/api/getAccountLoad","/api/issueDirectives","/api/changePassword","/api/cardActivation","/api/CustomerAccountCardDetails","/api/accountLoad","/api/updateConsumersProfile","/api/verifyCvv"
,"/api/updatePrepaidCardStatus","/api/getStatementData");
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception
return super.authenticationManagerBean();
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception
auth.userDetailsService(userSecurityService).passwordEncoder(SecurityUtils.passwordEncoder());
@Bean
public BCryptPasswordEncoder encoder()
return new BCryptPasswordEncoder();
@Bean
public FilterRegistrationBean corsFilter()
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
bean.setOrder(0);
return bean;
现在当我调用这些配置时
http://localhost:8080/oauth/token
这让我可以访问和刷新这是我想要的。但是现在
我有一个看起来像这样的控制器
@GetMapping("/users")
public Map<String,String> getUsers()
Map<String,String> map = new HashMap<>();
map.put("name","sagar");
map.put("job","developers");
return map;
所以我这样称呼这个端点
http://localhost:8080/users
现在我期望的是,每当我调用这个端点时,这个调用都应该被验证。但它只是返回我
"name": "sagar",
"job": "developers"
即使我不发送任何令牌。我希望这个端点被允许使用角色SCT_USER
。
为什么这没有发生?
【问题讨论】:
【参考方案1】:请仔细查看我的SecurityConfig版本
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class SecurityConfig extends WebSecurityConfigurerAdapter
@Autowired
private ClientDetailsService clientDetailsService;
/*@Autowired
private SecurityHandler securityHandler;
@Autowired
private UserSecurityService userSecurityService;
*/
private static final String[] PUBLIC_MATCHERS =
"/css/**",
"/js/**",
"/images/**",
"/",
"**/",
"/newUser",
"/forgetPassword",
"/login",
"**/uploads/**",
"/assets/**",
"/api/updateCardStatus",
"/fonts/**",
"/users"
;
/* @Override
protected void configure(HttpSecurity http) throws Exception
http
.authorizeRequests()
*//* antMatchers("/**").*//*
.antMatchers(PUBLIC_MATCHERS).
permitAll().anyRequest().authenticated();
http
.authorizeRequests()
.antMatchers("/admin").hasAnyRole("ROLE_ADMIN").and()
.formLogin().loginPage("/login").permitAll().failureUrl("/login?error")
.successHandler(securityHandler)
.and()
.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/?logout").deleteCookies("remember-me").permitAll()
.and()
.rememberMe();
*/
@Override
protected void configure(HttpSecurity http) throws Exception
http
.csrf().disable()
.anonymous().disable()
.authorizeRequests()
.antMatchers("/api-docs/**").permitAll().anyRequest().authenticated();
@Override
public void configure(WebSecurity web) throws Exception
web.ignoring()
.antMatchers("/api/updateCardStatus","*/uploads/***","/api/getUsersDetail","/api/getStudentDetails","/api/getAccountLoad","/api/issueDirectives","/api/changePassword","/api/cardActivation","/api/CustomerAccountCardDetails","/api/accountLoad","/api/updateConsumersProfile","/api/verifyCvv"
,"/api/updatePrepaidCardStatus","/api/getStatementData");
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception
return super.authenticationManagerBean();
@Autowired
public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception
auth.inMemoryAuthentication()
.withUser("admin")
.password("pass")
.roles("ADMIN", "USER").and()
.withUser("appuser")
.password("pass123").roles("USER");
/*@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception
auth.userDetailsService(userSecurityService).passwordEncoder(SecurityUtils.passwordEncoder());
*/
@Bean
public PasswordEncoder encoder()
return NoOpPasswordEncoder.getInstance();
@Bean
public FilterRegistrationBean corsFilter()
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
bean.setOrder(0);
return bean;
@Bean
@Autowired
public TokenStoreUserApprovalHandler userApprovalHandler(TokenStore tokenStore)
TokenStoreUserApprovalHandler handler = new TokenStoreUserApprovalHandler();
handler.setTokenStore(tokenStore);
handler.setRequestFactory(new DefaultOAuth2RequestFactory(clientDetailsService));
handler.setClientDetailsService(clientDetailsService);
return handler;
@Bean
@Autowired
public ApprovalStore approvalStore(TokenStore tokenStore) throws Exception
TokenApprovalStore store = new TokenApprovalStore();
store.setTokenStore(tokenStore);
return store;
这里有两个重点
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
还有
@Override
protected void configure(HttpSecurity http) throws Exception
http
.csrf().disable()
.anonymous().disable()
.authorizeRequests()
.antMatchers("/api- docs/**").permitAll().anyRequest().authenticated();
别忘了在你有 access("hasRole('SCT_USER')")
的 ResourceServerConfig 中修正你的错字
而不是
access("hasRole('USER')")
我已经为您的代码创建了测试示例。 https://github.com/alex-petrov81/***-answers/tree/master/spring-boot-endpoint-not-auth
【讨论】:
不是我已经提供了Securityconfig类的代码 仔细检查您的代码后,我发现了一个错误:hasRole('SCT_USER'),但在您的凭据中,您使用的是 USER 角色。我很快就会改变我的答案 这修复了它。非常感谢。我花了几个小时,我仍然无法检测到它们。这个@Order 注解有什么作用? 在 1.5.x 版本之后 OAuth2 资源服务器顺序设置为 SecurityProperties.ACCESS_OVERRIDE_ORDER - 1 现在其优先级肯定低于基本的 WebSecurityConfigurerAdapter 顺序。所以它导致指定 @Order 注释来恢复 WebSecurityConfigurerAdapter 顺序。它在 Spring 过滤器链中启用 OAuth 过滤器。 看来这个订单的东西弄乱了我的其他网址。就像我打电话给 localhost:8080/admin 它之前打开了 admin.html 页面。但在保留订单注释后,它现在返回一些 xml 错误。我怎么说例如localhost:8080/api**(将其视为api),剩余的url是正常的重定向url以上是关于Spring Boot 端点未经过身份验证的主要内容,如果未能解决你的问题,请参考以下文章
Spring boot SAML 2 身份验证对象 null
Spring-Boot REST 服务基本 http 身份验证排除一个端点
Spring boot 2.1.x 如何使用基本身份验证保护执行器端点