Apache Wicket + Spring Security ve Hatırla beni (remember-me) seçeneği
Prş 10 Haz 2010 18:19:49 | 1 yorum
Ne yaptım: Basit bir web uygulaması içerisinde, güvenlik mekanizması yerleştirdim.
Nasıl yaptım : Apache Wicket + Spring and Spring Security ve remember me(hatırla beni) seçeneği gerçekleştirildi.
Neden bu yazıyı yazdım : İnternet üzerinde Spring ve Spring Security ile alakalı bir çok yazı okudum fakat her ne hikmetse tam olarak istediğim bütün bir çözüm bulamadım (Belki ben yanlış aratmış olabilirim). Bu eksikliği kapatmak için bu yazıyı yazdım.
Detaylar:
İşlemlere başlamadan önce, kullanıcı adı, şifre ve rollerin alınacağı tablo ve verileri aşağıda veriyorum.
CREATE TABLE `musteri_rol` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`musteri_id` int(11) DEFAULT NULL,
`rol_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
/*Data for the table `musteri_rol` */
insert into `musteri_rol`(`id`,`musteri_id`,`rol_id`) values (1,1,1),(2,1,2),(3,2,1);
----------------------------------------------------------------------
CREATE TABLE `musteriler` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`eposta` varchar(100) DEFAULT NULL,
`password` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
/*Data for the table `musteriler` */
insert into `musteriler`(`id`,`eposta`,`password`) values (1,'altuga@gmail.com','6e8cd7f743f933158ce8e777136cda9c'),(2,'mehmetc@gmail.com','6e8cd7f743f933158ce8e777136cda9c');
----------------------------------------------------------------------
DROP TABLE IF EXISTS `roller`;
CREATE TABLE `roller` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`rol_ismi` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
/*Data for the table `roller` */
insert into `roller`(`id`,`rol_ismi`) values (1,'ROLE_USER'),(2,'ROLE_ADMIN');
Kullanıdığım ana teknolojiler.
- Spring version : 3.0.2.RELEASE
- Spring Security version :3.0.2.RELEASE
- Wicket version : 1.4.8
Daha da detay :
İşte hikaye; Bir adet gizli ve sadece bazı kişilerin erişebileceği bir sayfamız var; İşte adımlar :
- Kullanıcı sayfaya gelir
- Kullanıcı "Go to Secured Page " bağlantısına tıklar
- Sistem kullanıcıdan kullanıcı adı ve şifre ister
- Eğer doğru kullanıcı ise; kişi gizli sayfayı görür, başarı !!! ve kişinin tarayıcısına çerez atılır. Bu çerezin amacı kişinin daha sonra sisteme geldiğinde tekrardan kullanıcı adı ve şifre girmesinin önüne geçmek bu sayede kullanıcı memnuniyetini artar.
- Eğer kullanıcı yanlış bilgi girerse :
- Eğer kişinin gizli sayfayı görmeye hakkı yoksa o zaman :
Şimdi gerekli parçaları açıklamaya çalışalım
MusteriDAO.java : Bu sınıfın amacı kullanıcıyı onaylamaktır; yani kullanıcı bilgileri doğru mu ? Değil mi ? Bu sorunun cevabını bu sınıf cevaplar
@Repository
@Transactional
@Service
public class MusteriDAO {
@Autowired
private SessionFactory sessionFactory;
/**
* finds user according to email address
* @param eposta, email address
* @return Musteri object
*/
public Musteri bul(String eposta) {
Session session = this.sessionFactory.getCurrentSession();
Criteria criteria = session.createCriteria(Musteri.class);
criteria.add(Restrictions.eq("eposta", eposta));
List sonuc = criteria.list();
if (sonuc!=null && sonuc.size()>0) {
Musteri musteri = sonuc.get(0);
return musteri;
}else {
return null;
}
}
/**
* Checks users email and password
* @param eposta email address
* @param sifre password(encryted)
* @return the result, true meaans everything is ok, if false then no way to go
*/
public boolean sifreDogruMu(String eposta, String sifre) {
Session session = this.sessionFactory.getCurrentSession();
Criteria criteria = session.createCriteria(Musteri.class);
criteria.add(Restrictions.eq("eposta", eposta));
criteria.add(Restrictions.eq("sifre", sifre));
List sonuc = criteria.list();
if (sonuc!=null && sonuc.size()>0) {
return true;
}else {
return false;
}
}
}
spring-context.xml : Basit bir Spring ayar dosyası. Öncelikle hibernate ve mysql ayarları için gerekli tanımlamaları yapıyoruz.
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/lang"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.0.2.xsd
http://www.springframework.org/schema/lang
http://www.springframework.org/schema/lang/spring-lang-2.0.xsd"
>
A -
Kullanıcı giriş sayfasına herhangi bir güvenlik çemberine almaması için filters="none" diyoruz. Aksi takdirde giriş sayfasını da şifreleyip sonsuz ve saçma güvenlikli bir sistem oluşturmak an meselesi.
B -
Spring sisteminin güzelliği ve zerafetini iyi yansıtan bir kısımdayız. Bu noktada web.xml dışında içsel filitreler kullanıyoruz. Filitre demek, her isteği (respond) alıp bakıp değerlendiren kod parçaları demek. Örneğin rememberMeProcessingFilter amacı kullanıcı sisteme başarılı bir şekilde bağlandığında, ona bir çerez atmak; sonra efendim ; logoutFilter amacı ise gelen giden istekler arasında "logout" diye kelime aramak, yani kullanıcı logout bağlantısına tıklamış ise, kullanıcıyı sistemden atar varsa çerezi siler.
C -
class="org.springframework.security.authentication.encoding.Md5PasswordEncoder"/>
class="com.foo.datasource.MyAuthenticationProvider">
Çok mu karışlık ? Hemen kısımlara bölelim.
MyUserDetailsService.java : Bu sınıfın büyük bir amacı vardır; Kullanıcıları eposta adreslerine göre bulur (bu sistemde kullanıcı adı == eposta adresi ), tabii bunu yaparken arka planda MusteriDAO.java kullanılmaktadır.
public class MyUserDetailsService implements UserDetailsService {
@Autowired
private MusteriDAO musteriDao;
public UserDetails loadUserByUsername(String eposta) throws UsernameNotFoundException, DataAccessException {
Musteri musteri = musteriDao.bul(eposta);
if (musteri!=null) {
ArrayList ga = new ArrayList();
List roller = musteri.getRolListesi();
for(Rol rol : roller) {
ga.add(new GrantedAuthorityImpl(rol.getRolIsmi()));
}
GrantedAuthority[] grantedAuthorities = new GrantedAuthority[ga.size()];
ga.toArray(grantedAuthorities);
MyUserDetails myUserDetails = new MyUserDetails(eposta, musteri.getSifre(), true, true, true, true, grantedAuthorities);
return myUserDetails;
} else {
throw new UsernameNotFoundException(eposta);
}
}
}
Bir sonraki faydalı sınıf Md5PasswordEncoder'dır ; Bu hali hazırda nazır olan bir Spring iç sınıfdır.
Vee...
MyAuthenticationProvider.java : Bu sınıfın amacı kullanıcı onaylamaktır. Ya devam ya tamam denilen kısım burasıdır. Geri kalan detayları atlıyoruz.
public class MyAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
........
@Override
protected UserDetails retrieveUser(String eposta, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
UserDetails loadedUser;
loadedUser = this.getUserDetailsService().loadUserByUsername(eposta);
if ( md5Encoder.isPasswordValid(loadedUser.getPassword(), authentication.getCredentials().toString(), null)) {
return loadedUser; // if it comes from directly from user
} else if (loadedUser.getPassword().equals(authentication.getCredentials().toString())) {
return loadedUser; // if it comes from cookie
}
throw new BadCredentialsException("Invalid Password");
}
......
}
D -
D -
Authentication manager; sağlayıcı/lar a (provider) ihtiyaç duyar; bizde burada istenilen 2 adet sağlayıcıyı verdik. Bu sağlayıcılardan bir tanesi form üzerinden yapılan kullanıcı kontrol işlemleri için (myAuthenticationProvider), diğeri ise çerez tabanlı kontrol için gerekli olan sağlayıcıdır (rememberMeAuthenticationProvider). Bu tanımlama sadece Spring 3.x ve üzeri sürümler için geçerlidir.
E -
class="org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices">
Yukaridaki 3 ayar bölümünün amacı, kullanıcın hareketlerini yakalamaktır. Örneğin kullanıcı giriş yaptığı an, o anı yakalayıp birşey yapmak istersek geçerli olacaktır (örneğin giriş yapan kullanıcıları saymak gibi ). Gerekli açıklamaları üzerlerine yazmaya çalıştım.
F -
"com.foo.datasource.MyRemembermeAuthenticationProvider">
Benim yazmış olduğum hatırla beni servisini MyRemembermeAuthenticationProvider; Spring sistemine tanıtıyorum.
MyRemembermeAuthenticationProvider.java : Bu sınıfın amacı; hatırla beni (remember-me) mekanizmasına, kullanıcıyı nasıl onaylayacağını göstermektir. Bizim zaten hali hazırda kullanıcıyı onaylama sistemimiz olduğundan, direk fazladan birşey yazmadık.
......
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
authentication = authenticationManager.authenticate
(new UsernamePasswordAuthenticationToken(userDetails.getUsername(), userDetails.getPassword()));
SecurityContextHolder.getContext().setAuthentication(authentication);
return authentication;
}
......G -
Sistemden çıkış için gerekli olan tanımlama.
Conclusion : Sizlere Wicket + Spring Security birleştirilmesini anlatmaya çalıştım. Tam bu arada Apache Shiro projesi 1.0 resmi sürümlerini yayınladılar. Apache Shiro hayatımda gördüğüm en basit ve kullanışlı Java güvenlik sistemidir. Apache Shiro'da bir şans vermenizi şiddetle öneririm.
Sevgiler.
Altuğ Bilgin ALTINTAŞ.
Source codes can be reachable from (It's a maven project):
Not : İngilizce okumak isteyenler için : http://altuga.wordpress.com/2010/06/05/apache-wicket-spring-security-with-remember-me-option/#comments
Altuğ Bilgin ALTINTAŞ.
References:
Source codes can be reachable from (It's a maven project):
Örneği çalıştırmak için, kodları bilgisayarınıza indirin ve konsoldan
> mvn jetty:run
sonra tarayıcıdan gidip : localhost:8080 yazıp sistemi test edebilirsiniz.
Not : İngilizce okumak isteyenler için : http://altuga.wordpress.com/2010/06/05/apache-wicket-spring-security-with-remember-me-option/#comments
Yorum
Murat Döner
19 ay önce
Sil
ya da