昨天提到的驗證方式是透過Spring AuthenticationManager中的inMemoryAuthentication如下
@Override
@Autowired
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
// TODO Auto-generated method stub
auth //Builder Design Pattern
.inMemoryAuthentication() //自訂Runtime時的使用者帳號
.withUser("admin") //新增user
.password("admin12345") //指定密碼
.roles("ADMIN", "USER") //指派權限群組
.and() //再新增使用者
.withUser("user")
.password("user12345")
.roles("USER");
}
使用者是事先coding好的,如果我們要自己實作一個實作一個Authentication Manager中的Authentication Provider(這裡指的是inMemoryAuthentication),可以自行新增使用者,則需要用到SecurityContext, UserDetails, UserDetailService等介面,說起來還真是有點麻煩,故需要分成兩天來介紹,今天先介紹實作一個UserDetailsService負責取得UserDetails物件,UserDetails存放使用者資訊,使用者登入後放入Authentication物件中,換句話說就是Spring Security所認識的使用者,首先先建立DneUser Domain class
@Entity
public class DneUser {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
@Column(length=50)
private String username;
@Column(length=50)
private String password;
@Column(length=50)
private boolean enabled;
@Column(length=20)
private String firstName;
@Column(length=20)
private String lastName;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
接著建立相關的DAO class(DneUserRepository/DneUserRepositoryImp)
DneUserRepository.java
public interface DneUserRepository {
void save(DneUser user);
List<DneUser> findAllUsers();
DneUser findByUserName(String username);
}
DneUserRepositoryImp.java
@Repository
@Transactional
public class DneUserRepositoryImp implements DneUserRepository {
@PersistenceContext
private EntityManager entityManager;
@Override
public void save(DneUser user) {
// TODO Auto-generated method stub
entityManager.persist(user);
}
@Override
public List<DneUser> findAllUsers() {
// TODO Auto-generated method stub
Query query=entityManager.createQuery("select u from User u");
List<DneUser> users=(List<DneUser>)query.getResultList();
return users;
}
@Override
public DneUser findByUserName(String username) {
// TODO Auto-generated method stub
Query query=entityManager.createQuery("select u from User u where u.username =:username");
query.setParameter("username", username);
return (DneUser) query.getSingleResult();
}
}
接著建立DneUserDetailsService class實作UserDetailsService介面,這個class的目的在於取得UserDetails,使用DAO可以得到使用者名稱與密碼,Authority部分需要自己寫一個helper class用使用者名稱當作判斷來給予Authority(這只是一種方式,也可以依據其他欄位來給予Authority),其Code如下:
@Component
public class DneUserDetailsService implements UserDetailsService {
@Autowired
private DneUserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
// TODO Auto-generated method stub
DneUser user=userRepository.findByUserName(username);
if(user==null){
throw new UsernameNotFoundException("Invalid username/password");
}
//用集合及一個helper class來取得user的擁有的role
Collection<? extends GrantedAuthority> authorities=
UserAuthorityUtils.createAuthorities(user);
//UserAuthorityUtils是helper class
return new User(user.getUsername(), user.getPassword(), authorities);
//這邊的User是指org.springframework.security.core.userdetails.User
//是UserDetails介面的實作,儲存使用者名稱、密碼及擁有權限
}
}
helper class code如下:
public class UserAuthorityUtils {
private static final List<GrantedAuthority> ADMIN_ROLES = AuthorityUtils
.createAuthorityList("ROLE_ADMIN", "ROLE_USER");
//利用Spring提供的AuthorityUtils中createAuthorityList將該群組加入相關roles
//以便用一個List變數就儲存所有roles
private static final List<GrantedAuthority> USER_ROLES = AuthorityUtils
.createAuthorityList("ROLE_USER");
public static Collection<? extends GrantedAuthority> createAuthorities(
DneUser user) {
String username = user.getUsername();
if (username.contains("admin")) { //帳號中含有admin,即有管理者之role
return ADMIN_ROLES;
}
return USER_ROLES; //否則則為一般使用者
}
}
這樣就完成第一步新增UserDetails以及透過DneUserDetailService來取得UserDetails物件,明天繼續下半部,如何將UserDetails放入SpringContext以及從SpringContext取得UserDetails資訊。