spring-security-oauth2:intercept-url的access字段IS_AUTHENTICATED_FULLY无法使用了
问题描述:
最近把spring-security-oauth2的版本更新到了最新版,发现路径限制的access属性已经不能再使用原有的字符串和hasRole等函数了,百度上找的都是旧版的用法,官网也没怎么看懂,求大佬支招
下面两种方式都试过了,还是没法启动。
<security:intercept-url pattern="/oauth/token" access="hasRole('ROLE_USER')" />
<security:intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY" />
<security:intercept-url pattern="/api/**" access="hasRole('ROLE_USER')" />
<security:intercept-url pattern="/api/**" access="IS_AUTHENTICATED_FULLY" />
Caused by: java.lang.IllegalArgumentException: Unsupported configuration attributes: [hasRole('ROLE_USER')]
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.afterPropertiesSet(AbstractSecurityInterceptor.java:176)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1804)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1741)
... 47 more
答
放棄了xml的配置方式,改為spring boot項目了。
授權配置:
package com.hbk.config;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;
import com.hbk.service.impl.MyUserDetailsService;
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
private static final String PROP_CLIENTID = "client";
private static final int PROP_TOKEN_VALIDITY_SECONDS = 43200;
@Autowired
private DataSource dataSource;
@Autowired
private MyUserDetailsService userDetailsService;
@Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
@Autowired
private AuthenticationManager authenticationManager;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.tokenStore(tokenStore())
/*使用密碼模式的時候需要此項*/
.authenticationManager(authenticationManager)
/*使用refresh_token需要添加此配置,否則無法寫入數據庫*/
.userDetailsService(userDetailsService)
/*允許的接口訪問類型*/
.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
/*因為強制使用了加密模式,所以secret的格式也需要經過加密才可以正常通過驗證*/
String finalSecret = new BCryptPasswordEncoder().encode("123456");
clients.inMemory()
.withClient(PROP_CLIENTID)
.scopes("all")
.authorities("ROLE_ADMIN", "ROLE_USER")
.authorizedGrantTypes("password", "refresh_token")
.secret(finalSecret)
.authorities("oauth2")
.accessTokenValiditySeconds(PROP_TOKEN_VALIDITY_SECONDS);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security
.checkTokenAccess("permitAll()")
.tokenKeyAccess("permitAll()")
/*允許表單提交*/
.allowFormAuthenticationForClients();
}
}
資源服務:
package com.hbk.config;
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.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
@Configuration
@EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
@Autowired
private CustomAuthenticationEntryPoint customAuthenticationEntryPoint;
@Bean
public CustomLogoutSuccessHandler customerLogoutSuccessHandler() {
return new CustomLogoutSuccessHandler();
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.exceptionHandling()
.authenticationEntryPoint(customAuthenticationEntryPoint)
.and()
.logout()
.logoutUrl("/oauth/logout")
.logoutSuccessHandler(customerLogoutSuccessHandler())
.and()
.authorizeRequests()
.antMatchers("/imgs/**").permitAll()
.antMatchers("/api/**").authenticated();
}
}
自定義logout處理:
package com.hbk.config;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.web.authentication.AbstractAuthenticationTargetUrlRequestHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.util.StringUtils;
public class CustomLogoutSuccessHandler extends AbstractAuthenticationTargetUrlRequestHandler implements LogoutSuccessHandler {
private static final String BEARER_AUTHENTICATION = "Bearer";
private static final String HEADER_AUTHORIZATION = "authorization";
@Autowired
private TokenStore tokenStore;
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
String token = request.getHeader(HEADER_AUTHORIZATION);
if (StringUtils.hasLength(token) && token.startsWith(BEARER_AUTHENTICATION)) {
OAuth2AccessToken accessToken = tokenStore.readAccessToken(token.split(" ")[0]);
if (accessToken != null) {
tokenStore.removeAccessToken(accessToken);
}
}
response.setStatus(HttpServletResponse.SC_OK);
}
}
自定義授權捕獲:
package com.hbk.config;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
@Component
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
private final Logger log = LoggerFactory.getLogger(CustomAuthenticationEntryPoint.class);
@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException, ServletException {
log.info("Pre-authenticated entry point called. Rejecting access");
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Access Denied");
}
}
Web安全配置:
package com.hbk.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.provider.expression.OAuth2MethodSecurityExpressionHandler;
import com.hbk.service.impl.MyUserDetailsService;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private MyUserDetailsService userDetailsService;
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
//配置全局设置
@Autowired
private void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
//设置UserDetailsService以及密码规则
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/test");
}
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean() ;
}
//开启全局方法拦截
@EnableGlobalMethodSecurity(prePostEnabled = true, jsr250Enabled = true)
public static class GlobalSecurityConfiguration extends GlobalMethodSecurityConfiguration {
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
return new OAuth2MethodSecurityExpressionHandler();
}
}
}
UserDetailsService實現類:
package com.hbk.service.impl;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import com.hbk.pojos.Permission;
import com.hbk.pojos.User;
import com.hbk.service.PermissionService;
import com.hbk.service.UserService;
@Service
public class MyUserDetailsService implements UserDetailsService {
@Autowired
private UserService userService;
@Autowired
private PermissionService permissionService;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userService.getByUsername(username);
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
if (user != null) {
//获取用户的授权
List<Permission> permissions = permissionService.findByAdminUserId(user.getId());
for (Permission permission : permissions) {
if (permission != null && StringUtils.hasLength(permission.getName())) {
GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(permission.getName());
authorities.add(grantedAuthority);
}
}
}
org.springframework.security.core.userdetails.User userDetail = new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), authorities);
return userDetail;
}
}
感謝這位老哥:(https://blog.csdn.net/Ybt_c_index/article/details/85067321 "")