OAuth 2:获取访问令牌的问题

时间:2016-03-30 14:39:16

标签: spring curl oauth spring-boot

我刚刚开始使用OAuth和Spring Boot,并做了一个基本的应用程序来看它的实际效果。

这是我的MySQL架构:

def signup
if request.post?
  puts "SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSs"
  @user = User.new(user_params)
  if @user.save
    flash[:notice] = t("flash.signup")
    #Weiterleitung nach erfolgreichem Anlegen
    redirect_to :controller => :startsites, :action => "index"
  end
else
  @user = User.new
end
end

数据:

CREATE TABLE `role` (
  `id` int(20) NOT NULL,
  `role` varchar(50) NOT NULL,
  PRIMARY KEY (`role`)
)

CREATE TABLE `user` (
  `name` varchar(255) DEFAULT NULL,
  `username` varchar(50) NOT NULL,
  `email` varchar(50) DEFAULT NULL,
  `password` varchar(500) DEFAULT NULL,
  `enabled` tinyint(1) DEFAULT '0',
  `activationkey` varchar(50) DEFAULT NULL,
  `resetpasswordkey` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`username`),
  KEY `name` (`name`)
)

CREATE TABLE `user_role` (
  `username` varchar(50) NOT NULL,
  `role` varchar(50) NOT NULL,
  `id` int(20) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `USER_FK` (`username`),
  KEY `ROLE_FK` (`role`),
  CONSTRAINT `ROLE_FK` FOREIGN KEY (`role`) REFERENCES `role` (`role`),
  CONSTRAINT `USER_FK` FOREIGN KEY (`username`) REFERENCES `user` (`name`)
)

代码:

INSERT INTO `role` VALUES ('1', 'ROLE_ADMIN');
INSERT INTO `role` VALUES ('3', 'ROLE_GUEST');
INSERT INTO `role` VALUES ('2', 'ROLE_USER');

INSERT INTO `user` VALUES ('Leonardo', 'leonardo', 'leonardo.mora@datys.cu', 'admin', '1', null, null);

INSERT INTO `user_role` VALUES ('leonardo', 'ROLE_ADMIN', '0');

OAuth配置:

/**
* My CustomUserDetailService
*/
@Service
public class CustomUserDetailService implements UserDetailsService {

    private final UserRepository userRepository;

    @Autowired
    public CustomUserDetailService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userRepository.findByUsername(username);
        if (user == null) {
            throw new UsernameNotFoundException(String.format("User %s does not exist!", username));
        }
        return new UserRepositoryUserDetails(user);
    }

    private static class UserRepositoryUserDetails extends User implements UserDetails {

        private UserRepositoryUserDetails(User user) {
            super(user);
        }

        @Override
        public Collection<? extends GrantedAuthority> getAuthorities() {
            return getRoles();
        }

        @Override
        public boolean isAccountNonExpired() {
            return true;
        }

        @Override
        public boolean isAccountNonLocked() {
            return true;
        }

        @Override
        public boolean isCredentialsNonExpired() {
            return true;
        }

        @Override
        public boolean isEnabled() {
            return getEnabled();
        }
    }
}

网络安全配置:

@Configuration
public class Oauth2JdbcSample extends WebSecurityConfigurerAdapter {

    private static final String RESOURCE_ID = "cenergy";

    /**
     * Esta clase es para configurar el servidor de recursos
     *
     * @author leonardo.mora
     */
    @Configuration
    @EnableResourceServer
    protected static class ResourceServer extends ResourceServerConfigurerAdapter {

        @Override
        public void configure(ResourceServerSecurityConfigurer resources)
                throws Exception {
            resources
                    .resourceId(RESOURCE_ID);
        }

        @Override
        public void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests()                    
                    .antMatchers("/users")
                    .authenticated();
        }
    }

    /**
     * Esta clase es para configurar el servidor de autorizacion
     *
     * @author leonardo.mora
     */
    @Configuration
    @EnableAuthorizationServer
    protected static class OAuth2Config extends AuthorizationServerConfigurerAdapter {

        private TokenStore tokenStore = new InMemoryTokenStore();

        @Autowired        
        private AuthenticationManager authenticationManager;

        @Autowired
        private CustomUserDetailService userDetailsService;

        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints)
                throws Exception {
            endpoints.tokenStore(this.tokenStore)
                    .authenticationManager(this.authenticationManager)
                    .userDetailsService(this.userDetailsService);
        }

        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            // @formatter:off          
            clients.inMemory()
                    .withClient("cenergy-client")
                    .authorizedGrantTypes("password")
                    .authorities("ROLE_ADMIN")
                    .scopes("read", "write")
                    .resourceIds(RESOURCE_ID)
                    .secret("123456")
                    .accessTokenValiditySeconds(300);
            // @formatter:on
        }

        @Bean
        @Primary
        public DefaultTokenServices tokenServices() {
            DefaultTokenServices tokenServices = new DefaultTokenServices();
            tokenServices.setSupportRefreshToken(true);
            tokenServices.setTokenStore(this.tokenStore);
            return tokenServices;
        }
    }
}

这是我的访问令牌请求:

public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private CustomUserDetailService userDetailsService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService);
    }

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.csrf().csrfTokenRepository(csrfTokenRepository());
    }

    private CsrfTokenRepository csrfTokenRepository() {
        HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
        repository.setSessionAttributeName("_csrf");
        return repository;
    }
}

给了我错误:

curl -v -H "Content-Type: application/json" \
cenergy-client:123456@localhost:9191/api/oauth/token \
-d grant_type=password -d username=leonardo -d password=admin

有什么问题?

1 个答案:

答案 0 :(得分:1)

对令牌端点的请求需要将其正文格式设置为application/x-www-form-urlencoded而不是application/json

curl -v -H "Content-Type: application/x-www-form-urlencoded"  \
  cenergy-client:123456@localhost:9191/api/oauth/token        \
  -d grant_type=password -d username=leonardo -d password=admin

这是在OAuth2规范中定义的(具体在Section 4.3.中的密码授权):

  

4.3.2。访问令牌请求

     

客户端使用。向令牌端点[...]发出请求   每个Appendix B“application / x-www-form-urlencoded”格式   HTTP请求实体中的UTF-8字符编码: