kzen.dev
  • Pertanyaan
  • Tag
  • Pengguna
Notifikasi
Imbalan
Registrasi
Setelah Anda mendaftar, Anda akan diberitahu tentang balasan dan komentar untuk pertanyaan Anda.
Gabung
Jika Anda sudah memiliki akun, masuk untuk memeriksa pemberitahuan baru.
Akan ada hadiah untuk pertanyaan, jawaban, dan komentar tambahan.
Lebih
Sumber
Sunting
 shaunlim
shaunlim
Question

Menerapkan AuthenticationProvider khusus di Spring Security 2.06

Saya menggunakan Spring Security untuk mengamankan aplikasi web Struts2. Karena keterbatasan proyek, saya menggunakan Spring Security 2.06.

Tim saya membuat API Manajemen Pengguna khusus yang mengautentikasi pengguna setelah mengambil parameter nama pengguna dan kata sandi, dan mengembalikan objek pengguna khusus yang berisi daftar peran dan atribut lain seperti email, nama, dll.

Dari pemahaman saya, kasus penggunaan Spring Security yang khas menggunakan UserDetailsService default untuk mengambil objek UserDetails; objek ini akan berisi (antara lain) bidang kata sandi yang akan digunakan oleh kerangka kerja untuk mengautentikasi pengguna.

Dalam kasus saya, saya ingin membiarkan API kustom kami melakukan otentikasi, kemudian mengembalikan objek UserDetails kustom yang berisi peran dan atribut lainnya (email, dll).

Setelah beberapa penelitian, saya menemukan bahwa saya dapat melakukan ini melalui implementasi kustom AuthenticationProvider. Saya juga memiliki implementasi kustom dari UserDetailsService dan UserDetails.

Masalah saya adalah saya tidak benar-benar mengerti apa yang seharusnya saya kembalikan di CustomAuthenticationProvider. Apakah saya menggunakan objek UserDetailsService kustom saya di sini? Apakah itu bahkan diperlukan? Maaf, saya benar-benar bingung.

CustomAuthenticationProvider:

public class CustomAuthenticationProvider implements AuthenticationProvider {

private Logger logger = Logger.getLogger(CustomAuthenticationProvider.class);

private UserDetailsService userDetailsService; //what am i supposed to do with this?

@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    UsernamePasswordAuthenticationToken auth = (UsernamePasswordAuthenticationToken) authentication;
    String username = String.valueOf(auth.getPrincipal());
    String password = String.valueOf(auth.getCredentials());

    logger.info("username:" + username);
    logger.info("password:" + password);
    /* what should happen here? */

    return null;  //what do i return?
}

@Override
public boolean supports(Class aClass) {
    return true;  //To indicate that this authenticationprovider can handle the auth request. since there's currently only one way of logging in, always return true
}

public UserDetailsService getUserDetailsService() {
    return userDetailsService;
}

public void setUserDetailsService(UserDetailsService userDetailsService) {
    this.userDetailsService = userDetailsService;
}

}

applicationContext-security.xml:

<beans:bean id="customUserDetailsService" scope="prototype" class="com.test.testconsole.security.CustomUserDetailsService"/>

<beans:bean id="customAuthenticationProvider" class="com.test.testconsole.security.CustomAuthenticationProvider">
    <custom-authentication-provider />
    <beans:property name="userDetailsService" ref="customUserDetailsService" />
</beans:bean>

Untuk meringkas, inilah yang saya butuhkan:

  1. Pengguna masuk melalui formulir web

  2. Otentikasi pengguna menggunakan API manajemen pengguna internal

  3. Untuk pengguna yang berhasil diautentikasi, isi GrantedAuthories, dll.

  4. Kembalikan entitas pengguna yang berisi peran/otoritas, dan atribut lain seperti email, nama, dll. Saya kemudian harus dapat mengakses objek ini seperti ini ...

     //spring security mendapatkan nama pengguna
     Authentication auth = SecurityContextHolder.getContext().getAuthentication();
     userName = auth.getName(); //dapatkan nama pengguna yang login
     logger.info("username: " + userName);
    
     //keamanan mendapatkan peran pengguna
     GrantedAuthority[] authorities = auth.getAuthorities();
     userRole = authorities[0].getAuthority();
     logger.info("peran pengguna: " + userRole);

Saya harap ini masuk akal. Setiap bantuan atau petunjuk akan dihargai!

Terima kasih!

Pembaruan:

Saya pikir, saya telah membuat beberapa kemajuan.

Saya memiliki objek Otentikasi kustom yang mengimplementasikan antarmuka Otentikasi:

public class CustomAuthentication implements Authentication {

    String name;
    GrantedAuthority[] authorities;
    Object credentials;
    Object details;
    Object principal;
    boolean authenticated;

    public CustomAuthentication(String name, GrantedAuthority[] authorities, Object credentials, Object details, Object principal, boolean
                                authenticated){
        this.name=name;
        this.authorities=authorities;
        this.details=details;
        this.principal=principal;
        this.authenticated=authenticated;

    }
    @Override
    public GrantedAuthority[] getAuthorities() {
        return new GrantedAuthority[0];  //To change body of implemented methods use File | Settings | File Templates.
    }

    @Override
    public Object getCredentials() {
        return null;  //To change body of implemented methods use File | Settings | File Templates.
    }

    @Override
    public Object getDetails() {
        return null;  //To change body of implemented methods use File | Settings | File Templates.
    }

    @Override
    public Object getPrincipal() {
        return null;  //To change body of implemented methods use File | Settings | File Templates.
    }

    @Override
    public boolean isAuthenticated() {
        return false;  //To change body of implemented methods use File | Settings | File Templates.
    }

    @Override
    public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
        //To change body of implemented methods use File | Settings | File Templates.
    }

    @Override
    public String getName() {
        return null;  
    }
}

dan memperbarui kelas CustomerAuthenticationProvider saya:

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        UsernamePasswordAuthenticationToken auth = (UsernamePasswordAuthenticationToken) authentication;
        String username = String.valueOf(auth.getPrincipal());
        String password = String.valueOf(auth.getCredentials());

        logger.info("username:" + username);
        logger.info("password:" + password);

        //no actual validation done at this time

        GrantedAuthority[] authorities = new GrantedAuthorityImpl[1];
        authorities[0] = new GrantedAuthorityImpl("ROLE_USER");

        CustomAuthentication customAuthentication = new CustomAuthentication("TestMerchant",authorities,"details",username,password,true);

    return customAuthentication;

    //return new UsernamePasswordAuthenticationToken(username,password,authorities); 
}

Ini berfungsi jika saya mengembalikan objek UsernamePasswordAuthenticationToken, tetapi jika saya mencoba mengembalikan CustomAuthentication, saya mendapatkan kesalahan berikut:

java.lang.ClassCastException: com.test.testconsole.security.CustomAuthentication cannot be cast to org.springframework.security.providers.UsernamePasswordAuthenticationToken
    at com.test.testconsole.security.CustomAuthenticationProvider.authenticate(CustomAuthenticationProvider.java:27)
    at org.springframework.security.providers.ProviderManager.doAuthentication(ProviderManager.java:188)
    at org.springframework.security.AbstractAuthenticationManager.authenticate(AbstractAuthenticationManager.java:46)
    at org.springframework.security.intercept.AbstractSecurityInterceptor.authenticateIfRequired(AbstractSecurityInterceptor.java:319)
    at org.springframework.security.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:258)
    at org.springframework.security.intercept.web.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:106)
    at org.springframework.security.intercept.web.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83)
    at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
    at org.springframework.security.ui.SessionFixationProtectionFilter.doFilterHttp(SessionFixationProtectionFilter.java:67)
    at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
    at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
    at org.springframework.security.ui.ExceptionTranslationFilter.doFilterHttp(ExceptionTranslationFilter.java:101)
    at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
    at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
    at org.springframework.security.providers.anonymous.AnonymousProcessingFilter.doFilterHttp(AnonymousProcessingFilter.java:105)
    at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
    at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
    at org.springframework.security.ui.rememberme.RememberMeProcessingFilter.doFilterHttp(RememberMeProcessingFilter.java:116)
    at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
    at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
    at org.springframework.security.wrapper.SecurityContextHolderAwareRequestFilter.doFilterHttp(SecurityContextHolderAwareRequestFilter.java:91)
    at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
    at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
    at org.springframework.security.ui.basicauth.BasicProcessingFilter.doFilterHttp(BasicProcessingFilter.java:174)
    at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
    at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
    at org.springframework.security.ui.AbstractProcessingFilter.doFilterHttp(AbstractProcessingFilter.java:278)
    at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
    at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
    at org.springframework.security.ui.logout.LogoutFilter.doFilterHttp(LogoutFilter.java:89)
    at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
    at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
    at org.springframework.security.context.HttpSessionContextIntegrationFilter.doFilterHttp(HttpSessionContextIntegrationFilter.java:235)
    at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
    at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
    at org.springframework.security.util.FilterChainProxy.doFilter(FilterChainProxy.java:175)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:236)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
    at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
    at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
    at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
    at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
    at org.mortbay.jetty.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:230)
    at org.mortbay.jetty.handler.HandlerCollection.handle(HandlerCollection.java:114)
    at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
    at org.mortbay.jetty.Server.handle(Server.java:326)
    at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:536)
    at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:915)
    at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:539)
    at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:212)
    at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:405)
    at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:409)
    at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)

Ini seperti ada sesuatu yang mengharapkan bukan sembarang objek Autentikasi, tetapi implementasi spesifiknya - UsernamePasswordAuthenticationToken. Hal ini membuat saya berpikir bahwa saya mungkin kehilangan komponen khusus lainnya ... mungkin filter?

36 2011-12-27T22:12:26+00:00 2
Shaun  the Sheep
Shaun the Sheep
Pertanyaan edit 28 Desember 2011 в 2:56
Pemrograman
java
spring
spring-security
Solution / Answer
Shaun  the Sheep
Shaun the Sheep
28 Desember 2011 в 12:29
2011-12-28T00:29:37+00:00
Lebih
Sumber
Sunting
#15060747

Jika Anda mengimplementasikan AuthenticationProvider Anda sendiri, Anda tidak perlu mengimplementasikan UserDetailsService jika Anda tidak menginginkannya. UserDetailsService hanya menyediakan DAO standar untuk memuat informasi pengguna dan beberapa kelas lain dalam kerangka kerja diimplementasikan untuk menggunakannya.

Biasanya, untuk mengotentikasi menggunakan nama pengguna dan kata sandi, Anda akan menginstansiasi DaoAuthenticationProvider dan menginjeksikannya dengan UserDetailsService. Itu mungkin masih menjadi pendekatan terbaik Anda. Jika Anda mengimplementasikan provider Anda sendiri, Anda bertanggung jawab untuk memastikan pengguna telah memberikan kata sandi yang benar dan sebagainya. Namun, dalam beberapa kasus ini adalah pendekatan yang lebih sederhana.

Untuk menjawab komentar Anda "apa yang seharusnya terjadi di sini? " dalam kode Anda, akan menjadi sesuatu seperti

@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
  UsernamePasswordAuthenticationToken auth = (UsernamePasswordAuthenticationToken) authentication;
  String username = String.valueOf(auth.getPrincipal());
  String password = String.valueOf(auth.getCredentials());

  logger.info("username:" + username);
  logger.info("password:" + password); // Don't log passwords in real app

  // 1. Use the username to load the data for the user, including authorities and password.
  YourUser user = ....

  // 2. Check the passwords match (should use a hashed password here).
  if (!user.getPassword().equals(password)) {
    throw new BadCredentialsException("Bad Credentials");
  }

  // 3. Preferably clear the password in the user object before storing in authentication object
  user.clearPassword();

  // 4. Return an authenticated token, containing user data and authorities  

  return new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities()) ;
}

Objek pengguna kemudian akan dapat diakses dengan menggunakan

Authentication.getPrincipal()

dan Anda dapat mengakses properti tambahan (email, dll) dengan men-castingnya ke implementasi pengguna kustom Anda.

Bagaimana Anda memuat data pengguna terserah Anda. Semua yang dipedulikan Spring Security di sini adalah antarmuka AuthenticationProvider.

Anda juga harus menyimpan kata sandi hash dan memvalidasi kata sandi yang disediakan menggunakan algoritma yang sama, bukan pemeriksaan kesetaraan sederhana.

Anthony Raymond
Anthony Raymond
Jawaban edit 30 Juli 2017 в 8:12
50
0
 jasonwhite01
jasonwhite01
3 Desember 2013 в 7:10
2013-12-03T19:10:18+00:00
Lebih
Sumber
Sunting
#15060748

terima kasih telah memposting ini Luke!

Menyelamatkan saya dari lebih banyak kerusakan otak.

Satu-satunya hal yang saya temui, bagi siapa saja yang peduli:

Pengaturan saya:

  • Grails 2.0.4
  • Groovy 1.8
  • spring-security-core 1.2.7.3
  • spring-security-ui 0.2
  • hibernate 2.0.4

Ketika menggunakan pendekatan sederhana/elegant yang sangat dihargai yang disarankan Luke, TIDAK mengimplementasikan objek UserDetails (atau UserDetailsService) khusus - dan - menggunakan objek domain Pengguna Anda sendiri yang tidak memperluas sesuatu yang khusus, Anda harus mengambil langkah ekstra jika Anda menggunakan tag khusus "sec" dari spring security (di halaman Anda tentunya):

Ketika Anda membuat instantiate UsernamePasswordAuthenticationToken dasar, non-kustom, Anda HARUS mengoperkan instantiation dari sesuatu yang memperluas Principal, sekali lagi, jika Anda ingin tag celah kustom keamanan musim semi Anda berfungsi. Saya melakukan sesuatu seperti ini, untuk membuatnya sesederhana mungkin (mereferensikan nilai objek domain pengguna saya di mana berguna/sesuai):

def principalUser = new org.springframework.security.core.userdetails.User(user.username, user.password, user.enabled, !user.accountExpired, !user.passwordExpired,!user.accountLocked, authorities)
def token = new UsernamePasswordAuthenticationToken(principalUser, presentedPassword, authorities)

Ini harus memenuhi kondisi yang diuji di grails.plugins.springsecurity.SecurityTagLib.determineSource() jadi, Anda tahu, halaman Anda yang menggunakan <sec:loggedInUserInfo> akan benar-benar dirender:

if (principal.metaClass.respondsTo(principal, 'getDomainClass')) {
            return principal.domainClass
}

Jika tidak, jika Anda menginstansiasi UsernamePasswordAuthenticationToken dengan objek domain Pengguna Anda (seperti yang ditunjukkan Luke dalam contohnya), metode lib tag keamanan (determineSource()) hanya akan melakukan yang terbaik dan mengembalikan nilai (meta) dari org.codehaus.groovy.grails.commons.DefaultGrailsDomainClass dan Anda akan mendapatkan kesalahan ketika tag mencari variabel anggota nama pengguna yang menyatakan:

 Error executing tag <sec:ifLoggedIn>: Error executing tag <sec:loggedInUserInfo>: No such property: username for class: org.codehaus.groovy.grails.commons.DefaultGrailsDomainClass

Singkatnya, tidak ada cara untuk menggunakan taglibs plugin spring-security-core di proyek grails saya, tidak ada cara untuk menggunakan taglibs DAN menggunakan kelas Pengguna domain kustom Anda untuk membuat token yang diteruskan dari filter Anda ke penyedia Anda.

Sekali lagi, satu baris kode tambahan adalah harga yang sangat kecil untuk dibayar :)

 jasonwhite01
jasonwhite01
Jawaban edit 3 Desember 2013 в 8:56
3
0
Related communities 3
Programmer JAVA indonesia
Programmer JAVA indonesia
1 757 pengguna
Buka telegram
jvmusergroup
jvmusergroup
354 pengguna
Bismillahirrohmanirohim. Perhatian! Grup ini merupakan ekspansi dari grup Forum Java Programmer Indonesia di Facebook. Silahkan berbagi pengalaman dan masalah seputar Java dan keluarganya. https://t.me/JVMIndonesia Admin : @hendisantika34
Buka telegram
Java Indonesia🇲🇨
Java Indonesia🇲🇨
153 pengguna
Programmer Java Indonesia. Grup ini digunakan untuk bertanya terkait materi belajar Java / fullstack Warning=> -dilarang promosi(izin adm -18+🔞 - berbicara sopan - no spam /boot Mohon ikut aturan grup belum di keluarkan
Buka telegram
Tambahkan pertanyaan
Kategori
Semua
Teknologi
Budaya / Rekreasi
Kehidupan / Seni
Ilmu Pengetahuan
Profesional
Bisnis
Pengguna
Semua
Baru
Populer
1
工藤 芳則
Terdaftar 6 hari yang lalu
2
Ирина Беляева
Terdaftar 1 minggu yang lalu
3
Darya Arsenyeva
Terdaftar 1 minggu yang lalu
4
anyta nuam-nuam (LapuSiK)
Terdaftar 1 minggu yang lalu
5
Shuhratjon Imomkulov
Terdaftar 1 minggu yang lalu
ID
JA
© kzen.dev 2023
Sumber
stackoverflow.com
di bawah lisensi cc by-sa 3.0 dengan atribusi