Bộ sưu tập

UserDetails & UserDetailsService trong Spring Security


https://codersontrang.com/2013/09/03/userdetails-userdetailsservice-trong-spring-security/

Như trong ví dụ của những bài viết trước, ta có thể thấy các thông tin xác thực và phân quyền cho người dùng trong hệ thống được cấu hình trong file spring-config-security.xml như dưới đây


 <security:authentication-manager>  
      <security:authentication-provider>  
           <security:user-service>  
                <security:user name="teacher" password="myteacher" authorities="ROLE_TEACHER"/>  
                <security:user name="student" password="mystudent" authorities="ROLE_STUDENT"/>  
           </security:user-service>  
      </security:authentication-provider>  
 </security:authentication-manager>       

Spring Security có một authentication manager để quản lý việc xác thực, các thông tin để xác thực và phân quyền sẽ được cung cấp bởi một authentication-provider. Bên trong authentication provider, thông tin cho mỗi một cá thể sẽ được gói vào trong một user và được quản lý bởi một user-service. User service sẽ làm nhiệm vụ cung cấp các thông tin về một user nào đó cho việc xác thực và phân quyền. Đó là các thành phần cơ bản của Spring Security.

Tuy nhiên ta có thể thấy với cách cấu hình như trên không mang nhiều tính chất thực tế. Trên thực tế, thông tin xác thực và phân quyền hay được lưu và lấy ra từ nguồn nào đó (ví dụ như database chẳng hạn) thay vì trong file cấu hình như trên. Và tùy thuộc từng hệ thống thì các thông tin này sẽ được lưu trữ trong những cấu trúc khác nhau. Chính vì vậy mà thông tin về user, và cách hành xử của user-service trong mỗi ứng dụng cũng sẽ khác nhau. Bài viết này sẽ trình bày cách để tạo ra user và user service riêng cho ứng dụng cụ thể.

Một user và user service phải cung cấp đầy đủ các api mà Spring Security yêu cầu. Spring Security đã cung cấp sẵn hai interface là UserDetailsUserDetailsService lần lượt phục vụ cho việc tạo ra một User và user service của riêng ứng dụng. Như trong ví dụ, ta sẽ tạo ra hai lớp là MyUserDetailsMyUserDetailsService lần lượt biểu diễn user và user service như dưới đây

springsecu_userdetail_userdetailservice_1

UserDetails.java

 package springsecure.userdetail;  
 import java.util.Collection;  
 import java.util.List;  
 import org.springframework.security.core.GrantedAuthority;  
 import org.springframework.security.core.userdetails.UserDetails;  
 public class MyUserDetails implements UserDetails{  
      private String userName;  
      private String password;  
      private List<GrantedAuthority> authorities;  
      public MyUserDetails(String userName, String password, List<GrantedAuthority> authorities){  
           this.userName = userName;  
           this.password = password;  
           this.authorities = authorities;  
      }  
      @Override  
      public Collection<? extends GrantedAuthority> getAuthorities() {  
           return authorities;  
      }  
      @Override  
      public String getPassword() {  
           return password;  
      }  
      @Override  
      public String getUsername() {  
           return userName;  
      }  
      @Override  
      public boolean isAccountNonExpired() {  
           return true;  
      }  
      @Override  
      public boolean isAccountNonLocked() {  
           return true;  
      }  
      @Override  
      public boolean isCredentialsNonExpired() {  
           return true;  
      }  
      @Override  
      public boolean isEnabled() {  
           return true;  
      }  
 }  

Lớp MyUserDetails cài đặt interface UserDetails của Spring Security và biểu diễn một đối tượng người dùng trong ứng dụng. Lớp này sẽ luu thông tin về xác thực (usernamepassword) và thông tin về phân quyền (list authorities) và lần lượt cài đặt các phương thức của interface UserDetails. Trong đó có một số phương thức quan chúng ta cần để ý đến là getUsername(), getPassword(), và getAuthorities().

MyUserDetailsService.java

 package springsecure.userdetailservice;  
 import java.util.ArrayList;  
 import java.util.List;  
 import org.springframework.security.core.GrantedAuthority;  
 import org.springframework.security.core.authority.SimpleGrantedAuthority;  
 import org.springframework.security.core.userdetails.UserDetails;  
 import org.springframework.security.core.userdetails.UserDetailsService;  
 import org.springframework.security.core.userdetails.UsernameNotFoundException;  
 import springsecure.userdetail.MyUserDetails;  

 public class MyUserDetailsService implements UserDetailsService{  
      @Override  
      public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {  
           if(!"codertiensinh".equalsIgnoreCase(userName)) throw new UsernameNotFoundException("User name not found");  
           String password = "a12345678";  
           List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();  
           SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_TEACHER");  
           authorities.add(authority);  
           MyUserDetails userDetail = new MyUserDetails(userName, password, authorities);  
           return userDetail;  
      }  
 }  

Lớp MyUserDetailsService cài đặt interface UserDetailsService, và cài đặt phương thức loadUserByUserName(). Phương thức này sẽ được gọi bởi Spring Security để lấy ra thông tin của tài khoản có username là username được nhập từ màn hình login. Thông tin của tài khoản có thể lấy ra từ nhiều nguồn và được tổng hợp lại ở phương thức này để trả về một đối tượng duy nhất là cài đặt của UserDetails. Ở ví dụ này, để đơn giản ta sẽ hard code thông tin của tài khoản với username là codertiensinh với mật khẩu tương ứng là a12345678 và có khả năng tương tác với hệ thống dưới quyền là ROLE_TEACHER. Còn lại trên thực tế, đây chính là chỗ mà ta gọi các hàm để lấy thông tin từ các database.

Bây giờ ta cấu hình lại để ứng dụng sử dụng MyUserDetailsService mà ta tạo ở trên cho việc xác thực như sau:

spring-config-security.xml

 <?xml version="1.0" encoding="UTF-8"?>   
 <beans xmlns="http://www.springframework.org/schema/beans"   
    xmlns:context="http://www.springframework.org/schema/context"   
    xmlns:mvc="http://www.springframework.org/schema/mvc"   
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    xmlns:security="http://www.springframework.org/schema/security"   
    xsi:schemaLocation="http://www.springframework.org/schema/mvc   
                              http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd  
                                http://www.springframework.org/schema/beans  
                                http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
                                http://www.springframework.org/schema/context  
                                http://www.springframework.org/schema/context/spring-context-3.0.xsd  
                                http://www.springframework.org/schema/security   
                                http://www.springframework.org/schema/security/spring-security-3.1.xsd">   
      <security:http auto-config="true">  
           <security:intercept-url pattern="/school/student/*" access="ROLE_STUDENT,ROLE_TEACHER"/>  
           <security:intercept-url pattern="/school/student-list" access="ROLE_TEACHER"/>  
           <security:form-login login-page="/school/login"   
                                    authentication-failure-url="/school/login?error=true"   
                                    username-parameter="username" password-parameter="password"/>  
           <security:logout logout-url="/school/logout" logout-success-url="/school/login"/>                           
           <security:remember-me key="remember-codersontrang"/>  
      </security:http>      
      <security:authentication-manager>  
           <security:authentication-provider user-service-ref="myUserDetailsService"/>  
      </security:authentication-manager>  

      <bean id="myUserDetailsService" class="springsecure.userdetailservice.MyUserDetailsService"></bean>       
 </beans>   

Bây giờ chạy lại ví dụ, ta thấy hệ thống sẽ chỉ được đăng nhập vào với tài khoản codertiensinh/a12345678. Còn lại sẽ trả về lời nhắn tài khoản xác thực không đúng như những gì ta vẫn thấy trong những bài viết trước.

3 comments on “UserDetails & UserDetailsService trong Spring Security

  1. Cái này có vẻ không ổn rồi anh ơi, thường thì app phải dùng thêm hibernate để lưu thông tin user, nhưng nếu thế thì trong file spring-config-security.xml phải config một property cho UserDetailsService refer đến một bean để connect database, nhưng mà nếu vậy thì không call bean đó dc, vì trong web.xml, cái file spring-config-security.xml được gọi lên từ đầu nên không lấy được bean trong spring-config-dao.xml. Bạn có thể giải thích chổ này không?

    Số lượt thích

  2. Hoàn toàn có thể gọi đến bean có liên quan đến kết nối database bạn ạ. Các file cấu hình sẽ được load ngang hàng nhau vào trong Spring Context. Nếu bạn có thêm file cấu hình spring-config-dao.xml nữa, bạn có thể cấu hình ở web.xml như sau:

     <context-param>  
       <param-name>contextConfigLocation</param-name>  
       <param-value>WEB-INF/spring-config-*.xml</param-value>  
      </context-param>  
    

    Số lượt thích

Trả lời

Mời bạn điền thông tin vào ô dưới đây hoặc kích vào một biểu tượng để đăng nhập:

WordPress.com Logo

Bạn đang bình luận bằng tài khoản WordPress.com Đăng xuất /  Thay đổi )

Google photo

Bạn đang bình luận bằng tài khoản Google Đăng xuất /  Thay đổi )

Twitter picture

Bạn đang bình luận bằng tài khoản Twitter Đăng xuất /  Thay đổi )

Facebook photo

Bạn đang bình luận bằng tài khoản Facebook Đăng xuất /  Thay đổi )

Connecting to %s