web-dev-qa-db-ja.com

SpringでClientDetailsS​​erviceConfigurerにJDBCを使用してクライアントを追加する方法は?

私はメモリ内のものを次のように機能させています:

_@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {

        clients.inMemory()
               .withClient("clientapp")
               .authorizedGrantTypes("password", "refresh_token")
               .authorities("USER")
               .scopes("read", "write")
               .resourceIds(RESOURCE_ID)
               .secret("123456");
}
_

JDBC実装を使用したいと思います。このために、次のテーブルを作成しました(MySQLを使用)。

_-- Tables for OAuth token store

CREATE TABLE oauth_client_details (
  client_id               VARCHAR(255) PRIMARY KEY,
  resource_ids            VARCHAR(255),
  client_secret           VARCHAR(255),
  scope                   VARCHAR(255),
  authorized_grant_types  VARCHAR(255),
  web_server_redirect_uri VARCHAR(255),
  authorities             VARCHAR(255),
  access_token_validity   INTEGER,
  refresh_token_validity  INTEGER,
  additional_information  VARCHAR(4096),
  autoapprove             TINYINT
);

CREATE TABLE oauth_client_token (
  token_id          VARCHAR(255),
  token             BLOB,
  authentication_id VARCHAR(255),
  user_name         VARCHAR(255),
  client_id         VARCHAR(255)
);

CREATE TABLE oauth_access_token (
  token_id          VARCHAR(255),
  token             BLOB,
  authentication_id VARCHAR(255),
  user_name         VARCHAR(255),
  client_id         VARCHAR(255),
  authentication    BLOB,
  refresh_token     VARCHAR(255)
);

CREATE TABLE oauth_refresh_token (
  token_id       VARCHAR(255),
  token          BLOB,
  authentication BLOB
);

CREATE TABLE oauth_code (
  code           VARCHAR(255),
  authentication BLOB
);
_

MySQLテーブルにクライアントを手動で追加する必要がありますか?

私はこれを試しました:

_clients.jdbc(dataSource).withClient("clientapp")
               .authorizedGrantTypes("password", "refresh_token")
               .authorities("USER")
               .scopes("read", "write")
               .resourceIds(RESOURCE_ID)
               .secret("123456");
_

Springが正しいものを正しいテーブルに挿入することを願っていますが、そうではないようです。 jdbc()の後にさらにチェーンできるのはなぜですか?

14
Wim Deblauwe

この質問はかなり古いですが、質問の元の問題に対する回答はありませんでした。 Springのoauth2実装に精通しているときに同じ問題に遭遇し、ClientDetailsServiceConfigurerJdbcClientDetailsServiceBuilderを介してプログラムによって追加されたクライアントを永続化しない理由を知りました(これは、ネット上のすべてのチュートリアルがWimによって投稿されたものと同様の例を示していたにもかかわらず、jdbc(datasource) configurerのメソッド)。コードをさらに詳しく調べたところ、その理由に気づきました。まあ、それは単に、_oauth_clients_details_テーブルを更新するコードが呼び出されないためです。不足しているのは、すべてのクライアントを構成した後の次の呼び出しです:.and().build()。したがって、Wimのコードは実際には次のようになります。

_clients.jdbc(dataSource).withClient("clientapp")
           .authorizedGrantTypes("password", "refresh_token")
           .authorities("USER")
           .scopes("read", "write")
           .resourceIds(RESOURCE_ID)
           .secret("123456").and().build();
_

これで、クライアントclientappがデータベースに永続化されました。

10
user35934

この手順はお控えください。

  1. サーバーを起動したら、SpringBootによって検出されるように、このschema.sqlをリソースフォルダー内に配置します。スプリングブートを使用しない場合、心配する必要はありません。このスクリプトを任意のMysqlアプリクライアント(phpmyadmin、HeidiSQL、Navicatなど)からインポートします。

    drop table if exists oauth_client_details; create table oauth_client_details ( client_id VARCHAR(255) PRIMARY KEY, resource_ids VARCHAR(255), client_secret VARCHAR(255), scope VARCHAR(255), authorized_grant_types VARCHAR(255), web_server_redirect_uri VARCHAR(255), authorities VARCHAR(255), access_token_validity INTEGER, refresh_token_validity INTEGER, additional_information VARCHAR(4096), autoapprove VARCHAR(255) ); drop table if exists oauth_client_token; create table oauth_client_token ( token_id VARCHAR(255), token LONG VARBINARY, authentication_id VARCHAR(255) PRIMARY KEY, user_name VARCHAR(255), client_id VARCHAR(255) ); drop table if exists oauth_access_token; create table oauth_access_token ( token_id VARCHAR(255), token LONG VARBINARY, authentication_id VARCHAR(255) PRIMARY KEY, user_name VARCHAR(255), client_id VARCHAR(255), authentication LONG VARBINARY, refresh_token VARCHAR(255) ); drop table if exists oauth_refresh_token; create table oauth_refresh_token ( token_id VARCHAR(255), token LONG VARBINARY, authentication LONG VARBINARY ); drop table if exists oauth_code; create table oauth_code ( code VARCHAR(255), authentication LONG VARBINARY ); drop table if exists oauth_approvals; create table oauth_approvals ( userId VARCHAR(255), clientId VARCHAR(255), scope VARCHAR(255), status VARCHAR(10), expiresAt TIMESTAMP, lastModifiedAt TIMESTAMP ); drop table if exists ClientDetails; create table ClientDetails ( appId VARCHAR(255) PRIMARY KEY, resourceIds VARCHAR(255), appSecret VARCHAR(255), scope VARCHAR(255), grantTypes VARCHAR(255), redirectUrl VARCHAR(255), authorities VARCHAR(255), access_token_validity INTEGER, refresh_token_validity INTEGER, additionalInformation VARCHAR(4096), autoApproveScopes VARCHAR(255) );
  2. OthorizationServer内にDataSource、authenticationManager、UserDetailsS​​erviceを挿入します

    _@Autowired private MyUserDetailsService userDetailsService; @Inject private AuthenticationManager authenticationManager; @Autowired private DataSource dataSource;_
  3. この2つのBeanを作成する必要があります

    @Bean public JdbcTokenStore tokenStore() { return new JdbcTokenStore(dataSource); } @Bean protected AuthorizationCodeServices authorizationCodeServices() { return new JdbcAuthorizationCodeServices(dataSource); }

    authorizationServerクラスの上にある@Configurationを忘れないでください

  4. Mysqlデータベースに作成されるようにクライアントアプリを構成します。clients.jdbc(dataSource).withClient("clientapp") .authorizedGrantTypes("password", "refresh_token") .authorities("USER") .scopes("read", "write") .resourceIds(RESOURCE_ID) .secret("123456");

    あなたはすでにこれをしました。

  5. 最も重要なこと(そして私はあなたがそれを忘れていたと思います...)は、AuthorizationServerEndpointsConfigurerを使用してエンドポイントを構成することです。

    endpoints.userDetailsService(userDetailsService) .authorizationCodeServices(authorizationCodeServices()).authenticationManager(this.authenticationManager).tokenStore(tokenStore()).approvalStoreDisabled();

そしてそれは男です、今それはうまくいくはずです;)

さらにお気軽にお問い合わせください...お手伝いさせていただきます

ツイーターからメッセージを送りました!

11
AndroidLover

@AndroidLoverの答えは良いですが、単純化することができます。 jdbcトークンストアが必要でない限り、oauth_access_token、oauth_refresh_tokenなどのテーブルを作成する必要はありません。

Jdbcクライアント詳細サービスのみが必要なので、必要なのは次のことだけです。
1。クライアント詳細テーブルoauth_client_detailsを作成します。例:

drop table if exists oauth_client_details;
    create table oauth_client_details (
    client_id VARCHAR(255) PRIMARY KEY,
    resource_ids VARCHAR(255),
    client_secret VARCHAR(255),
    scope VARCHAR(255),
    authorized_grant_types VARCHAR(255),
    web_server_redirect_uri VARCHAR(255),
    authorities VARCHAR(255),
    access_token_validity INTEGER,
    refresh_token_validity INTEGER,
    additional_information VARCHAR(4096),
    autoapprove VARCHAR(255)
    );

2.たとえば、UserDetailインターフェイスを実装するユーザーモデルを作成します(この場合は、Spring jpaを使用しています。mybatis、jdbcなどを使用できます)。

@Entity
@Table(name = "users")
public class User implements UserDetails {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "user_id", nullable = false, updatable = false)
private String id;

@Column(name = "username", nullable = false, unique = true)
private String username;

@Column(name = "password", nullable = false)
private String password;

@Column(name = "enabled", nullable = false)
@Type(type = "org.hibernate.type.NumericBooleanType")
private boolean enabled;

public String getId() {
    return id;
}

public void setId(String id) {
    this.id = id;
}

public void setUsername(String username) {
    this.username = username;
}

public void setPassword(String password) {
    this.password = password;
}

public void setEnabled(boolean enabled) {
    this.enabled = enabled;
}

@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
    List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
    authorities.add((GrantedAuthority) () -> "ROLE_USER");
    return authorities;
}

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

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

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

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

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

@Override
    public boolean isEnabled() {
        return this.enabled;
    }
}

3.カスタムユーザー詳細サービスを作成します。あなたの実装では、あなたのdaoサービス(私の場合、jpaRepositoryを注入しました)とあなたのdaoサービス[〜#〜] must [〜#〜]を検索するメソッドが必要ですユーザー名別のユーザー:

@Service("userDetailsService")
public class UserService implements UserDetailsService {

@Autowired
UserRepository userRepository;

@Override
public UserDetails loadUserByUsername(String userName) throws 
UsernameNotFoundException {
    return userRepository.findByUsername(userName);
}
}

4.最後に、認証サーバーを設定します。

@Configuration
@EnableAuthorizationServer
public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {

@Autowired
@Qualifier("dataSource")
DataSource dataSource;

@Autowired
@Qualifier("userDetailsService")
private UserDetailsService userDetailsService;


@Autowired
private AuthenticationManager authenticationManager;

@Override
public void configure(AuthorizationServerEndpointsConfigurer configurer) {
    configurer
            .authenticationManager(authenticationManager)                
            .approvalStoreDisabled()
            .userDetailsService(userDetailsService);
}


@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception 
{
    clients
            .jdbc(dataSource)
            .inMemory().withClient("my-trusted-
client").secret("secret").accessTokenValiditySeconds(3600)
            .scopes("read", "write").authorizedGrantTypes("password", 
"refresh_token").resourceIds("resource");
}
}
2
haozhechen
@Override
public void configure(ClientDetailsServiceConfigurer configurer) throws Exception {

    JdbcClientDetailsService jdbcClientDetailsService = new JdbcClientDetailsService(dataSource);

    if(!jdbcClientDetailsService.listClientDetails().isEmpty() ) {          
    jdbcClientDetailsService.removeClientDetails(CLIEN_ID);     
    }

    if(jdbcClientDetailsService.listClientDetails().isEmpty() ) {
        configurer.jdbc(dataSource).withClient(CLIEN_ID).secret(encoder.encode(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).and().build();                
    }       
    configurer.jdbc(dataSource).build().loadClientByClientId(CLIEN_ID); 
}

ここでは、データベーステーブルoauth_client_detailsにクライアントが存在することを確認しています。クライアントが存在する場合、最初はエラーなしで機能するため、そのエントリを削除しますが、アプリケーションを再起動すると、データベースにエントリを追加するときに主キーエラーが発生します。それが私がこのコードを追加した理由です:

 if(!jdbcClientDetailsService.listClientDetails().isEmpty() ) { 

    jdbcClientDetailsService.removeClientDetails(CLIEN_ID);

    }

クライアントエントリを削除した後、ここにクライアントを追加する必要があります。クライアントを追加するためのコードは次のとおりです。

if(jdbcClientDetailsService.listClientDetails().isEmpty() ) {
        configurer.jdbc(dataSource).withClient(CLIEN_ID).secret(encoder.encode(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).and().build();

    } 

このコードでは、アプリケーションを再起動した後に毎回クライアントエントリを削除するため、必要に応じて構成を変更できます。

ここでは、すべてのクライアントの詳細をロードしています。

configurer.jdbc(dataSource).build().loadClientByClientId(CLIEN_ID);

エラーなしで問題なく動作します。ありがとう

1
swapnil kadam

私の2セントを追加します。

起動時にDB構造を初期化している場合(前を削除して)、たとえば次のようにします。

@Bean
public DataSourceInitializer dataSourceInitializer(DataSource dataSource) {
    //...setting dataSource and databasePopulator
}
private DatabasePopulator databasePopulator() {
    //...adding your schema script
}
@Bean
public DataSource dataSource() {
    //...setting driverclassname, url, etc
}

@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
    //...
    clients.jdbc(this.dataSource()).withClient("example").(...).build()
}

注意してください。

Beanは特定の順序で作成する必要がないため、古いテーブルに行を挿入し、スキーマから新しいものに置き換えるときに状況を把握することができます。だから、しばらく疑問に思うかもしれませんが、なぜそれでもまだ行が挿入されないのですか?私はこれが誰かを助けることを願っています。

0
user2501323