上一篇文章中因爲是第一次使用security這種機制。有些操做不太完備或者是爲了實現某個功能走的彎路較多,這一章節是對上一章節的概括總結。固然也還有不完善地方。後期再應用中不斷更新
安全機制html
<dependencies> <!-- 安全校驗 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> </dependencies>
git clone https://github.com/spring-projects/spring-security.git
WebSecurityConfigurerAdapter 提供了默認安全校驗機制的配置
查看源碼:git
protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .anyRequest().authenticated() //任何請求須要進行身份校驗 .and() .formLogin() //提交表單驗證方式 .and() .httpBasic(); }
爲了改變其默認行爲,咱們能夠提供一個子類覆蓋WebSecurityConfigurerAdapter的默認行爲github
@EnableWebSecurity public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/public/**").permitAll() .antMatchers("/students/**").hasRole("ADMIN") .and() .formLogin() .and() .httpBasic(); } }
進行web安全配置web
@EnableWebSecurity public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/public/**").permitAll() //受權請求 .antMatchers("/students/**").hasRole("ADMIN") //受權請求 .and() .formLogin() .loginPage("/login") //自定義登陸頁面 .permitAll() //容許全部人訪問該路由 .and() .csrf() .disable() //暫時禁用csrc不然沒法提交 .httpBasic(); } }
添加/login跳轉服務spring
@Controller public class IndexController { @GetMapping("/error") public String error() { return "redirect:/error_page.html"; } @GetMapping("/login") public String login(Model model, @RequestParam(value = "error", required = false) String error) { if (error != null) { model.addAttribute("error", "用戶名或密碼錯誤"); } return "forward:/login_page.html"; } }
提供登陸頁面數據庫
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登陸頁面</title> </head> <body> <h2>自定義登陸頁面</h2> <hr> <form action="/login" method="POST" name="f"> 用戶名<input type="text" name="username"/> <br> 密碼 <input type="password" name="password"> <br> <input type="submit" value="登陸"> </form> </body> </html>
默認訪問'/logout'即完成退出功能,默認security機制會進行以下操做安全
固然,咱們也能夠自定義退出功能session
@EnableWebSecurity public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/public/**").permitAll() .antMatchers("/students/**").hasRole("ADMIN") .and() .formLogin() .loginPage("/login") //自定義登陸頁面 .permitAll() //容許全部人訪問該路由 .and() .logout() //自定義登出操做 .logoutUrl("/logout") .logoutSuccessUrl("/login") .logoutSuccessHandler((req,resp,auth)->{ //登出成功處理函數 System.out.println("logout success"); resp.sendRedirect("/login?logout"); }) .invalidateHttpSession(true) .addLogoutHandler((req,resp,auth)->{ //登出處理函數 System.out.println("logout------"); }) //.deleteCookies("") .and() .csrf() .disable() //暫時禁用csrc不然沒法提交 .httpBasic(); } }
重寫用戶服務app
/** * 用戶認證服務 * */ @Bean @Override protected UserDetailsService userDetailsService() { //建立基於內存用戶管理對象 InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager(); //自定義權限 Collection<GrantedAuthority> adminAuth = new ArrayList<>(); adminAuth.add(new SimpleGrantedAuthority("ADMIN")); //自定義用戶 User u = new User("terry", "123321", true, true, true, true, adminAuth); manager.createUser(u); return manager; }
作法與基於內存相似,不過基於內存是本身建立用戶對象,而基於jdbc須要從數據庫中查詢數據而後爲身份驗證提供數據。實際上驗證操做仍是有security來完成,咱們無非是給security提供用戶信息而已。maven
@EnableWebSecurity public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .anyRequest().authenticated() .and() .formLogin() .failureHandler((req,resp,authException)->{ System.out.println(authException.getMessage()); resp.sendRedirect("/login?error"); }) .loginPage("/login") //自定義登陸頁面 .successHandler((req,resp,auth)->{ //獲取登陸者信息 Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); if (principal != null && principal instanceof UserDetails) { UserDetails user = (UserDetails) principal; System.out.println("login success:"+user.getUsername()); //維護在session中 req.getSession().setAttribute("userDetail", user); resp.sendRedirect("/"); } }) .permitAll() //容許全部人訪問該路由 .and() .logout() //自定義登出操做 .logoutUrl("/logout") .logoutSuccessUrl("/login") .logoutSuccessHandler((req,resp,auth)->{ //登出成功處理函數 System.out.println("logout success"); resp.sendRedirect("/login?logout"); }) .invalidateHttpSession(true) .addLogoutHandler((req,resp,auth)->{ //登出處理函數 System.out.println("logout------"); }) //.deleteCookies("") .and() .csrf() .disable() //暫時禁用csrc不然沒法提交 .httpBasic(); } /** * 基於JDBC用戶認證服務 * */ @Bean @Override protected UserDetailsService userDetailsService() { return new UserDetailsService() { @Autowired private UserMapper userMapper; @Autowired private UserRoleMapper userRoleMapper; @Override public UserDetails loadUserByUsername(String name) throws UsernameNotFoundException { UserDetails userDetails = null; try { User user = userMapper.findByUsername(name); if(user != null) { List<UserRole> urs = userRoleMapper.findByUserId(user.getId()); Collection<GrantedAuthority> authorities = new ArrayList<>(); for(UserRole ur : urs) { String roleName = ur.getRole().getName(); SimpleGrantedAuthority grant = new SimpleGrantedAuthority(roleName); authorities.add(grant); } //封裝自定義UserDetails類 userDetails = new MyUserDetails(user, authorities); } else { throw new UsernameNotFoundException("該用戶不存在!"); } } catch (Exception e) { e.printStackTrace(); } return userDetails; } }; } } /** * 自定義用戶身份信息 * */ class MyUserDetails implements UserDetails { // 用戶信息 private User user; // 用戶角色 private Collection<? extends GrantedAuthority> authorities; public MyUserDetails(User user, Collection<? extends GrantedAuthority> authorities) { super(); this.user = user; this.authorities = authorities; } /** * */ private static final long serialVersionUID = 1L; @Override public Collection<? extends GrantedAuthority> getAuthorities() { return authorities; } @Override public String getPassword() { return this.user.getPassword(); } @Override public String getUsername() { return this.user.getUsername(); } @Override public boolean isAccountNonExpired() { return !this.user.getState().equals(User.STATE_ACCOUNTEXPIRED); } @Override public boolean isAccountNonLocked() { return !this.user.getState().equals(User.STATE_LOCK); } @Override public boolean isCredentialsNonExpired() { return !this.user.getState().equals(User.STATE_TOKENEXPIRED); } @Override public boolean isEnabled() { return !this.user.getState().equals(User.STATE_NORMAL); } }