前天無法註冊新使用者問題已找到,主要是EntityManager跟Transaction沒有設定好,今已可work,另外加入一個enabled欄位,註冊畫面如下,
點選Add後,導向首頁如下
表示註冊後setCurrentUser有生效,使用者在註冊後順便登入。
接著要介紹Spring Security支援的密碼加密,例如MD5, SHA-256等,是透過hashing的方法產生雜湊碼來加密,不過上述提到的兩種加密安全性還是有被破解的風險(這太專業了),對於開發者來說,Spring Security提o.s.s.crypto.bcrypt.BCryptPasswordEncoder物件來加密密碼,原理是除了加原本的密碼做hashing外,另外加入一組salt key,以避免有心人是以Rainbow Table的方式倒推密碼,示意圖如下(擷取自Spring Security 3.1)
要做密碼加密首先,要於SecurityConfig中設定Password Encoder參數,如下,另加入當存取權限不足時,AccessDenied的導向網址,其Code如下:
@EnableWebSecurity //Enable springFliterChain
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private DneUserDetailsService dneUserDetailsService;
@Override
protected void configure(HttpSecurity http) throws Exception {
// TODO Auto-generated method stub
http.
exceptionHandling()
.accessDeniedPage("/403") //存取被拒時導往的URL
.and()
.authorizeRequests()
.antMatchers("/resources/**").permitAll() //resource資料夾靜態資料可匿名存取
// .anyRequest().permitAll()//邏輯有誤,以下規則全不適用
.antMatchers("/userlist").hasAuthority("ROLE_ADMIN")
.antMatchers("/dcn/add").hasAuthority("ROLE_ADMIN")//必須是admin才可以存取
.antMatchers("/dcn/**") //對象為所有網址
.authenticated() //存取必須通過驗證
.and()
.formLogin()
......
@Override
@Autowired
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
// TODO Auto-generated method stub
auth
.userDetailsService(dneUserDetailsService) //換成userDetailsService
.passwordEncoder(new BCryptPasswordEncoder()); //密碼加密
}
}
另外,在DneUserRepository persist時,必須對原本的密碼以BCryptPasswordEncoder加密,其Code如下:
@Repository
@Transactional
public class DneUserRepositoryImp implements DneUserRepository {
@PersistenceContext
private EntityManager entityManager;
@Override
public void save(DneUser user) {
// TODO Auto-generated method stub
PasswordEncoder passwordEncoder= new BCryptPasswordEncoder(); //密碼加密
user.setPassword(passwordEncoder.encode(user.getPassword())); //以加密後的密碼覆蓋原輸入的密碼
entityManager.persist(user);
}
........
}
為了測試加密是否成功以及測試自訂存取被拒,新增兩個RequestMapping, /userlist以及/403,其code如下
@Controller
public class DefaultController {
@Autowired
private DneUserRepository dneUserRepository;
......
@RequestMapping(value="/userlist", method=RequestMethod.GET)
public String getUserList(Model model){
List<DneUser> users=dneUserRepository.findAllUsers(); //取得所有user
model.addAttribute("users", users);
return "UserList";
}
@RequestMapping(value="/403", method=RequestMethod.GET)
public String showAccessDeniedPage(){
return "403";
}
}
在剛剛的SecurityConfig中userlist網頁只有Admin可以存取,故以Patrick登入後,若點選User List連結,則出現畫面如下
若改以admin登入,則可以看到所有的使用者,可以看到密碼已被加密
另外順便一提SecurityConfig的antMatchers順序是有關係的,例如如果anyRequest().permitAll()設定在其他規則比較嚴格條件的前面的話,Spring Security判斷符合條件,就不會往下在走,意思是最鬆的規則應該在放在最後面,越是嚴格的規則要放在前面,否則,把下面的程式碼註解拿掉的話,則任何人無須登入即可看到新增DCN號碼,畫面如下
.authorizeRequests()
.antMatchers("/resources/**").permitAll() //resource資料夾靜態資料可匿名存取
// .anyRequest().permitAll()//邏輯有誤,以下規則全不適用
.antMatchers("/userlist").hasAuthority("ROLE_ADMIN")
.antMatchers("/dcn/add").hasAuthority("ROLE_ADMIN")//必須是admin才可以存取
.antMatchers("/dcn/**") //對象為所有網址
.authenticated() //存取必須通過驗證
.and()
.formLogin()
......
明天繼續介紹對如何Secure Method