সর্বশেষ সম্পাদনা করেছেন রিমন রনবীর (১৬-০৩-২০১৭ ১২:৫৬)

টপিকঃ স্প্রিং সিকিউরিটিঃ 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();
        }
    }
}

আর্টিকেলটা নিজের ব্লগে অবশ্য পোস্ট করেছি। রেফেরেন্স হিসেবে থাকলো।

রিমন রনবীর'এর ওয়েবসাইট

লেখাটি CC by 3.0 এর অধীনে প্রকাশিত