【问题标题】:TokenEndpoint : Handling error: InvalidGrantException, Bad credentials with right credentialsTokenEndpoint:处理错误:InvalidGrantException,具有正确凭据的错误凭据
【发布时间】:2019-12-02 16:56:42
【问题描述】:

我目前正在开发自己的项目,该项目应该有自己的使用 spring-boot 和 spring-oauth 的 oauth 身份验证服务器。

我明白了

TokenEndpoint : 处理错误:InvalidGrantException,错误的凭据,即使名称和密码都是正确的。

我将我的用户保存在 mysql 中,并使用bCrypt 对密码进行编码。 以下是我的配置

我试过了:

  • 密码中的{noop}
  • 尝试了 passwordEncoder Bean 的不同实现
  • 尝试使用自定义 UserDetailsS​​erviceImplementation
    @Configuration
    @EnableAuthorizationServer
    public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

        @Autowired
        private AuthenticationManager authenticationManager;

        @Autowired
        private PasswordEncoder passwordEncoder;

        /**
         * Setting up the endpointsconfigurer authentication manager.
         * The AuthorizationServerEndpointsConfigurer defines the authorization and token endpoints and the token services.
         * @param endpoints
         * @throws Exception
         */
        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
            endpoints.authenticationManager(authenticationManager);
            endpoints.tokenStore(getTokenStore());
        }

        @Bean
        public TokenStore getTokenStore(){
            return new InMemoryTokenStore();
        }

        /**
         * Setting up the clients with a clientId, a clientSecret, a scope, the grant types and the authorities.
         * @param clients
         * @throws Exception
         */
        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            clients
                    .inMemory()
                    .withClient("my-trusted-client")
                    .authorizedGrantTypes("password")
                    .authorities("ROLE_USER").scopes("read","write","trust")
                    .resourceIds("oauth2-resource").accessTokenValiditySeconds(5000).secret(passwordEncoder.encode("secret"));
        }

        /**
         * We here defines the security constraints on the token endpoint.
         * We set it up to isAuthenticated, which returns true if the user is not anonymous
         * @param security the AuthorizationServerSecurityConfigurer.
         * @throws Exception
         */
        @Override
        public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
            security.checkTokenAccess("isAuthenticated()");
        }

    }

    public class CustomUserDetails implements UserDetails {

        private String password;
        private String username;
        private Collection<? extends GrantedAuthority> authorities;

        public CustomUserDetails(User user) {
            this.username = user.getUsername();
            this.password = user.getPassword();
            this.authorities = translate(user.getRole());
        }


        private Collection<? extends GrantedAuthority> translate(Role role) {
            List<GrantedAuthority> authorities = new ArrayList<>();
            String roleName = role.getRole().toUpperCase();
            authorities.add(new SimpleGrantedAuthority(roleName));
            return authorities;
        }

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

        @Override
        public String getPassword() {
            return password;
        }

        @Override
        public String getUsername() {
            return username;
        }

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

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

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

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

    }

        @Configuration
        @EnableResourceServer
        public class ResourceServerConfig extends WebSecurityConfigurerAdapter {

            @Override
            public void configure(HttpSecurity http) throws Exception {
                http
                        .authorizeRequests()
                        .antMatchers("/","/home","/register","/login").permitAll()
                        .antMatchers("/private/**").authenticated()
                        .antMatchers("/post").authenticated()
                        .antMatchers("/post/postComment").authenticated()
                        .antMatchers(HttpMethod.DELETE , "/post/**").hasAuthority("ROLE_ADMIN");
            }

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

    @SpringBootApplication
    @EnableAuthorizationServer
    public class BackendApplication {

        @Autowired
        private PasswordEncoder passwordEncoder;

        public static void main(String[] args) {
            SpringApplication.run(BackendApplication.class, args);
        }
        @Bean
        public PasswordEncoder passwordEncoder(){
            return new BCryptPasswordEncoder();
        }

        /**
         * Password grants are switched on by injecting an AuthenticationManager.
         * Here, we setup the builder so that the userDetailsService is the one we coded.
         * @param builder
         * @param repository
         * @throws Exception
         */
        @Autowired
        public void authenticationManager(AuthenticationManagerBuilder builder, UserRepository repository, UserService userService) throws Exception {
            if (repository.count()==0) {
                userService.save(new User("admin", "{noop}adminPassword", new Role("ROLE_USER")));
            }
            builder.userDetailsService(userDetailsService(repository)).passwordEncoder(passwordEncoder);
        }

        /**
         * We return an istance of our CustomUserDetails.
         * @param repository
         * @return
         */
        private UserDetailsService userDetailsService(final UserRepository repository) {
            return username -> new CustomUserDetails(repository.findByUsername(username));
        }
    }

警告信息: 2019-07-24 15:46:42.341 WARN 73936 --- [nio-8088-exec-4] os.s.o.provider.endpoint.TokenEndpoint:处理错误:InvalidGrantException,错误凭据

网址:http://localhost:8088/oauth/token 请求是带有参数的 url-www-form-encoded:

  • grant_type:password
  • 用户名:管理员
  • 密码:admin密码

和“基本身份验证”,用户名“my-trusted-client”,密码“secret”。

【问题讨论】:

  • 用户密码错误。我认为您必须在 userService.save(new User("admin", "{noop}adminPassword", new Role("ROLE_USER"))); 使用 BCrypt 编码器而不是 noop 编码器
  • 同样的问题。我可以删除 {noop} 并添加 {bcrypt} 或者只使用普通的“adminPassword”。凭据仍然很差
  • 不,您必须使用编码密码:` {bcrypt}$2y$12$G1/7T9nRB9SNBF93Kpe..uhzy2W1mHqoaJZ2zxK.1T​​J6mRHWM902a`。
  • 或使用密码编码器:userService.save(new User("admin", passwordEncoder.encode("adminPassword"), new Role("ROLE_USER"))); 在启动应用程序之前不要忘记从数据库中删除用户。
  • 你能解决这个问题吗?我也一样。

标签: spring spring-security oauth-2.0


【解决方案1】:

由于未提供请求,我不得不猜测:当配置为 ClientDetailsServiceConfigurer 时,您不应该对客户端密码进行编码。

.secret(passwordEncoder.encode("secret")) 替换为.secret("secret"),异常应该会消失。

【讨论】:

  • 如果我不编码“秘密”,我会得到 BCryptPasswordEncoder :编码密码看起来不像 BCrypt 和“错误:未经授权”。编辑:请求现在在我的问题中
  • 好的,试试.secret("{noop}secret") 并使用NoOpPasswordEncoder 进行测试或使用.secret("{bcrypt}"+passwordEncoder.encode("secret")) 进行BcryptPasswordEncoder。如果这会成功,我会更新答案。
  • Still BCryptPasswordEncoder : 编码密码看起来不像 BCrypt。
  • 只是具体一点:我想使用 BcryptPasswordEncoder,因为它将在未来的生产中使用
【解决方案2】:

.secret("{bcrypt}" + passwordEncoder.encode("secret")) 用于 my-trusted-client 和 .secret("{bcrypt}" + passwordEncoder.encode("adminPassword")) 用于管理员。并且:检查是否在调试会话中使用了 BcryptPasswordEncoder。

【讨论】:

    猜你喜欢
    • 2018-09-19
    • 2020-03-10
    • 2014-09-12
    • 2015-09-18
    • 2011-10-27
    • 2015-12-04
    • 1970-01-01
    • 2013-08-31
    • 2017-09-23
    相关资源
    最近更新 更多