在閱讀本文以前能夠先看看springsecurity的基本執行流程,下面我展現一些核心配置文件,後面給出完整的整合代碼到git上面,有興趣的小夥伴能夠下載進行研究git
使用maven工程構建項目,首先須要引入最核心的依賴,github
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
因爲這裏咱們整合的項目進行了先後端分離,因此咱們首先須要自定義登陸成功和失敗,登出成功的自定義處理類web
其實就是實現不一樣的handler便可:1.首先咱們來看登陸成功的處理類spring
/** * 處理登陸驗證成功的類 * @author zhoukebo * @date 2018/9/4 */ @Component public class FuryAuthSuccessHandler implements AuthenticationSuccessHandler { /**Json轉化工具*/ @Autowired private ObjectMapper objectMapper; @Override public void onAuthenticationSuccess(HttpServletRequest request,HttpServletResponse response, Authentication authentication) throws IOException{ SysUser userDetails = (SysUser)authentication.getPrincipal(); System.out.println("管理員 " + userDetails.getUsername() + " 登陸"); Map<String,String> map=new HashMap<>(2); map.put("code", "200"); map.put("msg", "登陸成功"); response.setContentType("application/json;charset=UTF-8"); response.getWriter().write(objectMapper.writeValueAsString(map)); } }
2.登陸驗證失敗的類json
/** * 處理登陸驗證失敗的類 * @author zhoukebo * @date 2018/9/4 */ @Component public class FuryAuthFailureHandler implements AuthenticationFailureHandler { @Autowired private ObjectMapper objectMapper; @Override public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException { System.out.println("登陸驗證失敗"); Map<String,String> map=new HashMap<>(2); map.put("code", "10001"); map.put("msg", exception.getMessage()); response.setContentType("application/json;charset=UTF-8"); response.getWriter().write(objectMapper.writeValueAsString(map)); } }
3.自定義處理註銷成功的類後端
/** * 處理註銷成功 * @author zhoukebo * @date 2018/9/4 */ @Component public class MyLogoutSuccessHandler implements LogoutSuccessHandler { /**Json轉化工具*/ @Autowired private ObjectMapper objectMapper; @Override public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException{ Map<String,String> map=new HashMap<>(2); map.put("code", "200"); map.put("msg", "登出成功"); response.setContentType("application/json;charset=UTF-8"); response.getWriter().write(objectMapper.writeValueAsString(map)); } }
4.自定義沒有權限的處理類安全
/** * 處理沒有權限的類 * @author zhoukebo * @date 2018/9/5 */ @Component public class RestAuthAccessDeniedHandler implements AccessDeniedHandler { @Autowired private ObjectMapper objectMapper; @Override public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e) throws IOException, ServletException { Map<String,String> map=new HashMap<>(2); map.put("code", "403"); map.put("msg", e.getMessage()); response.setContentType("application/json;charset=UTF-8"); response.getWriter().write(objectMapper.writeValueAsString(map)); } }
而後對springsecurity進行詳細的配置須要繼承WebSecurityConfigurerAdapter類,下面是配置文件的詳情springboot
/** * spring Security配置安全控制中心 * * @author zhoukb */ @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class WebSecurityConfig extends WebSecurityConfigurerAdapter { /** * 依賴注入自定義的登陸成功處理器 */ @Autowired private FuryAuthSuccessHandler furyAuthSuccessHandler; /** * 依賴注入自定義的登陸失敗處理器 */ @Autowired private FuryAuthFailureHandler furyAuthFailureHandler; /** * 依賴注入自定義的註銷成功的處理器 */ @Autowired private MyLogoutSuccessHandler myLogoutSuccessHandler; /** * 註冊沒有權限的處理器 */ @Autowired private RestAuthAccessDeniedHandler restAuthAccessDeniedHandler; /***注入自定義的CustomPermissionEvaluator*/ @Bean public DefaultWebSecurityExpressionHandler webSecurityExpressionHandler() { DefaultWebSecurityExpressionHandler handler = new DefaultWebSecurityExpressionHandler(); handler.setPermissionEvaluator(new CustomPermissionEvaluator()); return handler; } /***注入咱們本身的登陸邏輯驗證器AuthenticationProvider*/ @Autowired private AuthenticationProvider authenticationProvider; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { //這裏可啓用咱們本身的登錄驗證邏輯 auth.authenticationProvider(authenticationProvider); } /** * 配置spring security的控制邏輯 */ @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() //"/login"不進行權限驗證 .antMatchers("/login").permitAll() .antMatchers("/favicon.ico").permitAll() .anyRequest().authenticated() //其餘的須要登錄後才能訪問 .and() .formLogin() //loginProcessingUrl用於指定先後端分離的時候調用後臺登陸接口的名稱 .loginProcessingUrl("/login") //配置登陸成功的自定義處理類 .successHandler(furyAuthSuccessHandler) //配置登陸失敗的自定義處理類 .failureHandler(furyAuthFailureHandler) .and() //loginProcessingUrl用於指定先後端分離的時候調用後臺註銷接口的名稱 .logout().logoutUrl("/logout") .logoutSuccessHandler(myLogoutSuccessHandler) .and() //配置沒有權限的自定義處理類 .exceptionHandling().accessDeniedHandler(restAuthAccessDeniedHandler) .and() .cors()//新加入 .and() .csrf().disable();// 取消跨站請求僞造防禦 } }
上面咱們配置了自定義的登陸邏輯的驗證MyAuthenticationProvider,和自定義的權限驗證CustomPermissionEvaluator代碼以下app
/** * 實現本身的AuthenticationProvider類,用來自定義用戶校驗機制 * @author zhoukebo * @date 2018/9/5 */ @Component public class MyAuthenticationProvider implements AuthenticationProvider { @Autowired private CustomerDetailService customerDetailService; @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { // 獲取表單輸入中返回的用戶名; String userName = (String) authentication.getPrincipal(); // 獲取表單中輸入的密碼; String password = (String) authentication.getCredentials(); // 這裏調用咱們的本身寫的獲取用戶的方法; UserDetails userInfo = customerDetailService.loadUserByUsername(userName); if (userInfo == null) { throw new BadCredentialsException("用戶名不存在"); } // 這裏咱們還要判斷密碼是否正確,這裏咱們的密碼使用BCryptPasswordEncoder進行加密的 if (!new BCryptPasswordEncoder().matches(password, userInfo.getPassword())) { throw new BadCredentialsException("密碼不正確"); } // 這裏還能夠加一些其餘信息的判斷,好比用戶帳號已停用等判斷。 Collection<? extends GrantedAuthority> authorities = userInfo.getAuthorities(); // 構建返回的用戶登陸成功的token return new UsernamePasswordAuthenticationToken(userInfo, password, authorities); } @Override public boolean supports(Class<?> authentication) { // 這裏直接改爲retrun true;表示是支持這個執行 return true; } }
/** * 咱們須要自定義對hasPermission()方法的處理, * 就須要自定義PermissionEvaluator,建立類CustomPermissionEvaluator,實現PermissionEvaluator接口。 * @author zhoukebo * @date 2018/9/5 */ @Component public class CustomPermissionEvaluator implements PermissionEvaluator { /** * 自定義驗證方法 * @param authentication 登陸的時候存儲的用戶信息 * @param targetDomainObject @PreAuthorize("hasPermission('/hello/**','r')") 中hasPermission的第一個參數 * @param permission @PreAuthorize("hasPermission('/hello/**','r')") 中hasPermission的第二個參數 * @return */ @Override public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) { // 得到loadUserByUsername()方法的結果 SysUser user = (SysUser)authentication.getPrincipal(); // 得到loadUserByUsername()中注入的權限 Collection<? extends GrantedAuthority> authorities = user.getAuthorities(); // 遍歷用戶權限進行斷定 for(GrantedAuthority authority : authorities) { UrlGrantedAuthority urlGrantedAuthority = (UrlGrantedAuthority) authority; String permissionUrl = urlGrantedAuthority.getPermissionUrl(); // 若是訪問的Url和權限用戶符合的話,返回true if(targetDomainObject.equals(permissionUrl)) { return true; } } return false; } @Override public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) { return false; } }
注意:上面的自定義權限要生效還須要在WebSecurityConfig上面加上註解@EnableGlobalMethodSecurity(prePostEnabled = true)cors
完成登陸邏輯還須要咱們實現UserDetailsService接口,以便系統可以根據用戶名去獲取用戶的信息,裏面還可加上本身的邏輯
/** * 須要自定義UserDetailsService實現spring security的UserDetailsService接口 * @author zhoukebo * @date 2018/9/4 */ @Service public class CustomerDetailService implements UserDetailsService { @Autowired SysUserRepository userRepository; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { SysUser user = userRepository.findByUsername(username); if (user == null) { throw new UsernameNotFoundException("用戶名不存在"); } List<SysRole> roles = user.getRoles(); //將全部的角色對應的資源權限所有放入user對應的grantedAuthority集合中 for (SysRole role : roles) { List<SysResource> resources = role.getResources(); List<GrantedAuthority> grantedAuthorities = new ArrayList<>(); for (SysResource resource : resources) { if (resource != null && resource.getResourceName()!=null) { GrantedAuthority grantedAuthority = new UrlGrantedAuthority(resource.getMethodPath(),resource.getResourceName()); grantedAuthorities.add(grantedAuthority); } } user.setGrantedAuthority(grantedAuthorities); } System.out.println("s:" + username); return user; } }
以上就完成了springboot和springsecurity的整合工做,demo中包含兩種自定義權限驗證,有興趣的小夥伴能夠自行在github上面下載下來研究,不懂得能夠交流,代碼有什麼不妥的地方也望你們互相指教