spring-security-oauth2:intercept-url的access字段IS_AUTHENTICATED_FULLY无法使用了

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 "")