本文在Spring Boot + Spring Security添加記住我功能 的基礎上進行修改html
- 在登陸的時候,在UserDetailService中認證並受權,修改UserDetailService
@Configuration public class UserDetailService implements UserDetailsService { @Autowired private PasswordEncoder passwordEncoder; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { // 模擬一個用戶,替代數據庫獲取邏輯 MyUser user = new MyUser(); user.setUserName(username); user.setPassword(this.passwordEncoder.encode("123456")); // 輸出加密後的密碼 System.out.println(user.getPassword()); //受權 真正的應用中會根據數據中的查詢得知 List<GrantedAuthority> authorities = new ArrayList<>(); if (StringUtils.equalsIgnoreCase("admin", username)) { authorities = AuthorityUtils.commaSeparatedStringToAuthorityList("admin"); } else { authorities = AuthorityUtils.commaSeparatedStringToAuthorityList("test"); } return new User(username, user.getPassword(), user.isEnabled(), user.isAccountNonExpired(), user.isCredentialsNonExpired(), user.isAccountNonLocked(), authorities); } }
- 新建自定義權限輔助類:
@Component public class MyAuthenticationAccessDeniedHandler implements AccessDeniedHandler { @Override public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException { response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); response.setContentType("application/json;charset=utf-8"); response.getWriter().write("很抱歉,您沒有該訪問權限"); } }
- 開啓權限註解並配置權限輔助類:
@Component @EnableGlobalMethodSecurity(prePostEnabled = true) // 開啓權限註解 public class MySecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private MyAuthenticationFailureHandler authenticationFailureHandler; @Autowired private MyAuthenticationSuccessHandler authenticationSuccessHandler; @Autowired private ValidateCodeFilter validateCodeFilter; @Autowired private UserDetailService userDetailService; @Autowired private DataSource dataSource; @Autowired private MyAuthenticationAccessDeniedHandler myAuthenticationAccessDeniedHandler; public PersistentTokenRepository persistentTokenRepository() { JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl(); jdbcTokenRepository.setDataSource(dataSource); jdbcTokenRepository.setCreateTableOnStartup(false); return jdbcTokenRepository; } @Bean public BCryptPasswordEncoder bCryptPasswordEncoder(){ return new BCryptPasswordEncoder(); } @Override protected void configure(HttpSecurity http) throws Exception { http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class) // 添加驗證碼校驗過濾器 .exceptionHandling() .accessDeniedHandler(myAuthenticationAccessDeniedHandler) // 配置輔助類 .and() .formLogin() // 表單登陸 // http.httpBasic() // HTTP Basic .loginPage("/authentication/require") // 登陸跳轉 URL .loginProcessingUrl("/login") // 處理表單登陸 URL .failureHandler(authenticationFailureHandler) // 處理登陸失敗 .successHandler(authenticationSuccessHandler) .and() .rememberMe() // 啓用rememberMe .tokenRepository(persistentTokenRepository()) // 配置 token 持久化倉庫 .tokenValiditySeconds(3600) // remember 過時時間,單爲秒 .userDetailsService(userDetailService) // 處理自動登陸邏輯 .and() .authorizeRequests() // 受權配置 .antMatchers("/authentication/require", "/login.html", "/code/image").permitAll() // 無需認證的請求路徑 .anyRequest() // 全部請求 .authenticated() // 都須要認證 .and().csrf().disable(); } }
- 修改IndexController:
@RestController public class IndexController { @GetMapping("index") public Object index(){ return SecurityContextHolder.getContext().getAuthentication(); } @GetMapping("/auth/admin") @PreAuthorize("hasAuthority('admin')") // 權限控制註解① public String authenticationTest() { return "您擁有admin權限,能夠查看"; } }
- 測試:
啓動項目:訪問http://localhost:8005/login.html ,填寫用戶名user密碼123456,提示以下git
訪問http://localhost:8005/auth/admin 提示以下:github
使用admin密碼123456登陸 提示以下:spring
訪問http://localhost:8005/auth/admin 提示以下:數據庫
注:json
①權限控制註解有:springboot
1.Spring Security自帶的@Secured註解;app
開啓註解:@EnableGlobalMethodSecurity(securedEnabled = true)ide
@Secured("ROLE_ADMIN") // 或者({"ROLE_ADMIN","ROLE_USER"}) public void test(){ ... }
2.JSR-250的@RolesAllowed註解;測試
@EnableGlobalMethodSecurity(jsr250Enabled = true)
@RolesAllowed("ROLE_ADMIN") public void test(){ ... }
3.表達式驅動的註解,包括@PreAuthorize、@PostAuthorize、@PreFilter和 @PostFilter
開啓註解: @EnableGlobalMethodSecurity(prePostEnabled = true)
//該註解用於方法前驗證權限,下方是:限制非VIP用戶提交blog的note字段字數不得超過1000字 //#form部分直接引用了方法中的同名參數。這使得Spring Security可以檢查傳入方法的參數,並將這些參數用於認證決策的制定 @PreAuthorize("hasRole('ROLE_ADMIN') and #form.note.length() <= 1000 or hasRole('ROLE_VIP')") public void writeBlog(Form form){ ... } 或者: //方法後調用權限驗證,校驗方法返回值 用戶名是否正確 //Spring Security在SpEL中提供了名爲returnObject 的變量。在這裏方法返回一個User對象,因此這個表達式能夠直接訪問user對象中的userName屬性。 @PreAuthorize("hasRole(ROLE_USER)") @PostAuthorize("returnObject.user.userName == principal.username") public User getUserById(long id){ ...
本文代碼運行正常
本文源代碼:https://github.com/ttdys/springboot/tree/master/springboot_security/05_role_permission