2016-01-27 11 views
6

mam w pamięci, co działa w następujący sposób:Jak dodać klienta przy użyciu JDBC dla ClientDetailsServiceConfigurer na wiosnę?

@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"); 
} 

Chciałbym użyć realizacji JDBC. W tym celu utworzyłem następujące tabele (używając 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 
); 

Czy muszę ręcznie dodawać klienta do tabel MySQL?

Próbowałem to:

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

Mając nadzieję, że wiosna będzie wstawić odpowiednie rzeczy w dobrych tabel, ale nie wydaje się, aby to zrobić. Dlaczego możesz dalej łączyć się po jdbc()?

Odpowiedz

0

To pytanie jest dość stare, ale żadna z odpowiedzi nie dała odpowiedzi na oryginalny problem pytającego. I natknął się w tym samym numerze dostając się znają z realizacji OAuth2 sprężyny i zastanawiał się, dlaczego ClientDetailsServiceConfigurer nie jest utrzymująca klientów, które programowo dodane przez JdbcClientDetailsServiceBuilder (który jest tworzony przez wywołanie metody jdbc(datasource) na Configurer), mimo że wszystko tutoriale w sieci pokazały podobny przykład, jak opublikowany przez Wima. Po głębszym wykopaniu kodu zauważyłem przyczynę. Cóż, dzieje się tak dlatego, że kod do aktualizacji tabeli oauth_clients_details nigdy nie jest wywoływany. Brakuje następującego połączenia po skonfigurowaniu wszystkich klientów: .and().build(). Więc, kod Wim musi faktycznie wyglądać następująco:

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

Et voila, klient clientapp jest teraz trwało do bazy danych.

8

Proszę odłogiem tej czynności:

  1. umieścić ten schema.sql wewnątrz folderu zasobów mają być wykrywane przez SpringBoot po uruchomieniu serwera. Jeśli nie korzystasz z bagażnika sprężyny nie martwi tylko importować ten skrypt z dowolnego klienta MySQL App (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. wstrzykiwać DataSource, authenticationManager, UserDetailsService wewnątrz OthorizationServer

    @Autowired private MyUserDetailsService userDetailsService; @Inject private AuthenticationManager authenticationManager; @Autowired private DataSource dataSource;
  3. trzeba będzie utworzyć te dwie fasoli

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

    i proszę nie zapomnieć o @Configu racja na szczycie swojej klasy AuthorizationServer

  4. skonfigurować klientów aplikacje mają być utworzone w bazie danych mysql: clients.jdbc(dataSource).withClient("clientapp") .authorizedGrantTypes("password", "refresh_token") .authorities("USER") .scopes("read", "write") .resourceIds(RESOURCE_ID) .secret("123456");

    już to zrobione.

  5. najważniejsze (i myślę, że zapomniałeś o tym ..) jest: aby skonfigurować punkty końcowe z AuthorizationServerEndpointsConfigurer:

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

i to jest to człowiek, teraz powinno działać;)

I nie krępuj się poprosić o więcej ... będę szczęśliwy, aby pomóc

Wysłałem Ci wiadomość z głośnika wysokotonowego!

+0

Podążyłem za twoją odpowiedzią i skonfigurowałem serwer tak jak wspomniałeś i pomysł. Ale dostaję następujący błąd. Masz jakiś pomysł? {"Timestamp": 1458109110864, ​​"status": 401, "error": "Unauthorized", "message": "Błąd tworzenia komponentu bean o nazwie" scopedTarget.clientDetailsService "zdefiniowany w ścieżce klasy resource [org/Spring Framework/hartowane/OAuth2/konfiguracji/adnotacji/konfiguracji/ClientDetailsServiceConfiguration.class] Fasola instancji poprzez metody fabryki nie powiodła się zagnieżdżony wyjątek org.springframework.beans.BeanInstantiationException: – Waruna

+0

udało się wystąpienia [org.springframework.security.oauth2.provider. ClientDetailsService]: Metoda fabryczna "clientDetailsService" zwróciła wyjątek, zagnieżdżony wyjątek to org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; zła gramatyka SQL [wstawić do oauth_client_details (client_secret, resource_ids, scope, authorized_grant_types, web_server_redirect_uri, authority, access_token_validity, refresh_token_validity, additional_information, autoapprove, client_id) wartości (?,?,?,?,?,?,?,?,?,?,?)]; – Waruna

+0

wyjątek zagnieżdżony to org.h2.jdbc.JdbcSQLException: nie znaleziono tabeli \ "OAUTH_CLIENT_DETAILS \"; Instrukcja SQL:????? \ nWstaw do oauth_client_details wartości (client_secret, resource_ids, zakres, authorized_grant_types, web_server_redirect_uri władze, access_token_validity, refresh_token_validity, additional_information, autoapprove, CLIENT_ID) (,,,,,,,,, ?,) [42102-190]”,«ścieżka»:«/ OAuth/żeton»} – Waruna

0

Odpowiedź @AndroidLover jest dobra, ale można ją uprościć. Nie musisz tworzyć tabel takich jak oauth_access_token, oauth_refresh_token itp., Chyba że potrzebujesz magazynu znaczników jdbc.

Ponieważ potrzebujesz tylko usługi szczegółowej klient jdbc, wszystko, co musisz zrobić, to:
1.utworzyć tabelę szczegółów klienta oauth_client_details, na przykład:

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. stworzenie modelu użytkownika, który implementuje interfejs UserDetail, na przykład (używam sprężyny WZP w tym przypadku można użyć mybatis, JDBC cokolwiek):

@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. utworzyć niestandardową usługę szczegółową dla użytkownika. Zauważ, że w implementacji, należy wprowadzić swoją usługę dao (w moim przypadku, wstrzyknęli jpaRepository.), a usługa dao MUST mieć metodę, aby znaleźć użytkownika o nazwie użytkownika .:

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

@Autowired 
UserRepository userRepository; 

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

4. Na koniec , skonfiguruj serwer uwierzytelniający:

@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"); 
} 
} 
Powiązane problemy