স্প্রিং সিকিউরিটিঃ UserDetailsService দিয়ে ইউজার অথেনটিকেশন

স্প্রিং সিকিউরিটি বেসিক অথেনটিকেশন নিয়ে আমার পূর্বের আর্টিকেলটি দেখুন এখানে

এই আর্টিকেলে আমরা UserDetailsService দিয়ে ডেটাবেইজে ইউজারের টেবিল থেকে আমরা ইউজারকে অথেন্টিকেট করব।

এজন্য ইউজারের Entity কে একটু সাজাতে গুছাতে হবে। User class এ ইমপ্লিমেন্ট করে দিন স্প্রিং সিকিউরিটির UserDetails interface।

User Entity টা হবে এরকমঃ

User.java
@Entity
public class User implements UserDetails {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
@NotNull
@Column(unique = true)
private String email;
private String password;
private String token;
@Embedded
private Address address;
private String phoneNumber;
private boolean enabled = true;
private boolean accountNonExpired = true;
private boolean accountNonLocked;
private boolean credentialsNonExpired = true;
@ElementCollection(fetch = FetchType.EAGER)
private Collection<String> roles;


@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<GrantedAuthority> authorityList = new ArrayList<>();
this.roles.forEach(r -> {
authorityList.add(new SimpleGrantedAuthority(r));
});
return authorityList;
}

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

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

@Override
public boolean isAccountNonExpired() {
return this.accountNonExpired;
}

@Override
public boolean isAccountNonLocked() {
return this.accountNonLocked;
}

@Override
public boolean isCredentialsNonExpired() {
return this.credentialsNonExpired;
}

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

public Long getId() {
return id;
}

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

public String getEmail() {
return this.email;
}

public void setEmail(String email) {
this.email = email;
}

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

public String getToken() {
return token;
}

public void setToken(String token) {
this.token = token;
}

public Address getAddress() {
return address;
}

public void setAddress(Address address) {
this.address = address;
}

public String getPhoneNumber() {
return phoneNumber;
}

public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}

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

public void setAccountNonExpired(boolean accountNonExpired) {
this.accountNonExpired = accountNonExpired;
}

public void setAccountNonLocked(boolean accountNonLocked) {
this.accountNonLocked = accountNonLocked;
}

public void setCredentialsNonExpired(boolean credentialsNonExpired) {
this.credentialsNonExpired = credentialsNonExpired;
}

public Collection getRoles() {
return this.roles;
}

public void setRoles(Collection<String> roles) {
this.roles = roles;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

}

এখানে @Override অ্যানোটেশন দেয়া মেথডগুলা UserDetails interface এর মেথড যেখানে আমি আমার User এর রেস্পেকটিভ ফিল্ডগুলা রিটার্ন করে দিয়েছি। মানে এখন থেকে স্প্রিং সিকিউরিটি চিনে নেবে কোনটা আমার কোন ফিল্ড।

 

আপনি যদি স্প্রিং সিকিউরিটিকে আপনার অ্যাপ্লিকেশনের কোডের সাথে জগাখিচুড়ি করতে না চান তবে একটু ভিন্ন অ্যাপ্রোচে এগুতে পারেন। সেটা নিচের দিকে দেখানো হবে। তবে আপাতত এভাবেই আমার ভালো লাগে, কারন স্প্রিং সিকিউরিটি ছাড়া অন্য কোন সিকিউরিটি ফ্রেমওয়ার্ক ভবিষ্যতে ইউজ করার সম্ভাবনা নাই।

এবার একটা সার্ভিস বিন তৈরি করুন। আমি এক্ষেত্রে নাম দিলাম CustomUserDetailsService যেটা স্প্রিং সিকিউরিটির এর UserDetailsService interface ইমপ্লিমেন্ট করবে।

CustomUserDetailsService.java
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private UserService userService;

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = this.userService.findByEmail(username);
if (user == null) throw new UsernameNotFoundException("No user found with this email " + username);
return user;
}
}

আমি এখানে UserDetails loadUserByUsername(String username)  মেথডে আর্গুমেন্ট হিসেবে দেয়া ইউজারনেম দিয়ে ইউজারকে খুঁজে বের করে এনে রিটার্ন করে দিয়েছি। ব্যাস কাজ এইটুকুই। স্প্রিং সিকিউরিটি বারকীটা আপনার জন্য হ্যাণ্ডেল করবে।

 

একটু আগে ভিন্ন অ্যাপ্রোচের কথা বলেছিলাম, যেখানে আপনার অ্য্যাপ্লিকেশনের কোডের সাথে স্প্রিং সিকিউরিটি কোডের কাপলিং হবে না।

এই অ্যাপ্রোচের চেহারাটা হতে পারে এরকমঃ

User.java
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
@NotNull
@Column(unique = true)
private String email;
private String password;
private String token;
@Embedded
private Address address;
private String phoneNumber;
private boolean enabled = true;
private boolean accountNonExpired = true;
private boolean accountNonLocked;
private boolean credentialsNonExpired = true;
@ElementCollection(fetch = FetchType.EAGER)
private Collection<String> roles;

public Long getId() {
return id;
}

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

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}

public String getPassword() {
return password;
}

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

public String getToken() {
return token;
}

public void setToken(String token) {
this.token = token;
}

public Address getAddress() {
return address;
}

public void setAddress(Address address) {
this.address = address;
}

public String getPhoneNumber() {
return phoneNumber;
}

public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}

public boolean isEnabled() {
return enabled;
}

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

public boolean isAccountNonExpired() {
return accountNonExpired;
}

public void setAccountNonExpired(boolean accountNonExpired) {
this.accountNonExpired = accountNonExpired;
}

public boolean isAccountNonLocked() {
return accountNonLocked;
}

public void setAccountNonLocked(boolean accountNonLocked) {
this.accountNonLocked = accountNonLocked;
}

public boolean isCredentialsNonExpired() {
return credentialsNonExpired;
}

public void setCredentialsNonExpired(boolean credentialsNonExpired) {
this.credentialsNonExpired = credentialsNonExpired;
}

public Collection<String> getRoles() {
return roles;
}

public void setRoles(Collection<String> roles) {
this.roles = roles;
}
}

CustomUserDetailsService.java
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private UserService userService;

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = this.userService.findByEmail(username);
if (user == null) throw new UsernameNotFoundException("No user found with this email " + username);
return new SecurityUser(user);
}

class SecurityUser extends User implements UserDetails{
private User user;

public SecurityUser(User user){
this.user = user;
}

@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<GrantedAuthority> authorityList = new ArrayList<>();
this.user.getRoles().forEach(r -> {
authorityList.add(new SimpleGrantedAuthority(r));
});
return authorityList;
}

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

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

@Override
public boolean isAccountNonExpired() {
return this.user.isAccountNonExpired();
}

@Override
public boolean isAccountNonLocked() {
return this.user.isAccountNonLocked();
}

@Override
public boolean isCredentialsNonExpired() {
return this.user.isCredentialsNonExpired();
}

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

Comments

  1. whoah this blog is wonderful i really like reading your articles.
    Stay up the great work! You already know, lots of
    persons are searching round for this info, you could help them greatly.

    ReplyDelete
  2. This is the perfect site for everyone who really wants to understand this topic.
    You realize so much its almost hard to argue with you (not that
    I personally will need to…HaHa). You certainly put a brand new spin on a subject that has
    been written about for decades. Great stuff, just wonderful! https://www.facebook.com/Vitamin-Shoppe-Coupon-Codes-1880283042254350/

    ReplyDelete
  3. It's a shame you don't have a donate button! I'd most certainly donate to this fantastic
    blog! I guess for now i'll settle for bookmarking and adding
    your RSS feed to my Google account. I look forward to fresh updates and will share this blog with my Facebook group.

    ReplyDelete
  4. Thank you for the good writeup. It in fact was a amusement account
    it. Look advanced to far added agreeable from you! However, how could we communicate?

    ReplyDelete
  5. Well send me an email at [email protected] spammer.

    ReplyDelete

Post a Comment

Popular posts from this blog

Deploy Spring Boot app in digitalocean cloud (or any cloud as long asyou have ssh access)

Upload large files : Spring Boot

User activity logging: Spring