本帖最后由 hydee 于 2018-5-23 19:00 编辑
1.Spring Security的认证规则
要编写自定义的认证规则,首先需要对Spring Security中的认证规则有一定的了解,下面简单介绍下Spring Security的认证规则。
1)在Spring Security中每个URL都是一个资源,当系统启动的时候,Spring Security会根据配置将所有的URL与访问这个URL所需要的权限的映射数据加载到Spring Security中。
2)当一个请求访问一个资源时,Spring Security会判断这个URL是否需要权限验证,如果不需要,那么直接访问即可。
3)如果这个URL需要进行权限验证,那么Spring Security会检查当前请求来源所属用户是否登录,如果没有登录,则跳转到登录页面,进行登录操作,并加载这个用户的相关信息
4)如果登录,那么判断这个用户所拥有的权限是否包含访问这个URL所需要的权限,如果有则允许访问,否则不予放行。 2.自定义认证和权限判断实现 2.1自定义UserDetailsService @Component public class CustomUserDetailsService implements UserDetailsService { @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { LogManager.getLogger("CustomUserDetailsService").info("loadUserByUsername invoke"); // 提供到数据库查询该用户的权限信息 // 关于角色和权限的转换关系在此处处理,根据用户与角色的关系、角色与权限的关系, // 此处伪造一些数据 // 伪造权限 AuthorityModel authority = new AuthorityModel("AUTH_WELCOME"); List<AuthorityModel> authorities = new ArrayList<>(); authorities.add(authority); AccountInfoModel account = new AccountInfoModel("oolong", "12345"); account.setAuthorities(authorities); return account; } } 2.2自定义AuthenticationProvider @Componentpublic class CustomUserDetailsAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider { @Autowired private UserDetailsService userDetailsService; public UserDetailsService getUserDetailService() { return this.userDetailsService; } public void setUserDetailService(UserDetailsService userDetailsService) { this.userDetailsService = userDetailsService; } @Override protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { } @Override protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { LogManager.getLogger("CustomUserDetailsAuthenticationProvider").info("retrieveUser invoke"); if (userDetailsService == null) { throw new AuthenticationServiceException(""); } UserDetails userDetails = userDetailsService.loadUserByUsername(username); if (userDetails == null) { throw new UsernameNotFoundException(username); } if (userDetails.getUsername().equals(authentication.getPrincipal().toString()) && userDetails.getPassword().equals(authentication.getCredentials().toString())) { return userDetails; } throw new BadCredentialsException(username + authentication.getCredentials()); } } 2.4自定义AccessDecisionManager @Componentpublic class CustomAccessDecisionManager implements AccessDecisionManager { @Override public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException { LogManager.getLogger("CustomAccessDecisionManager").info("decide invoke"); if (configAttributes == null) { return; } if (configAttributes.size() <= 0) { return; } Iterator<ConfigAttribute> authorities = configAttributes.iterator(); String needAuthority = null; while(authorities.hasNext()) { ConfigAttribute authority = authorities.next(); if (authority == null || (needAuthority = authority.getAttribute()) == null) { continue; } LogManager.getLogger("CustomAccessDecisionManager").info("decide == " + needAuthority); for (GrantedAuthority ga : authentication.getAuthorities()) { if (needAuthority.equals(ga.getAuthority().trim())) { return; } } } throw new AccessDeniedException("No Authority"); } @Override public boolean supports(ConfigAttribute attribute) { return true; } @Override public boolean supports(Class<?> clazz) { return true; } } 3.实现组合配置 在Spring MVC中,Spring Security是通过过滤器发挥作用的,因此我们就爱那个决策管理器与数据加载放到一个过滤器中,然后将这个过滤器插入到系统的过滤器链中。 @Configuration @ComponentScan(basePackageClasses={TempHook.class}) @EnableWebSecuritypublic class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private CustomUserDetailsAuthenticationProvider customAuthenticationProvider; @Autowired private CustomAccessDecisionManager customAccessDecisionManager; @Autowired private CustomSecurityMetadataSource customSecurityMetadataSource; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(customAuthenticationProvider); } @Override protected void configure(HttpSecurity http) throws Exception { http.addFilterAfter(customFilterSecurityInterceptor(), ExceptionTranslationFilter.class); http.formLogin(); } @Bean public FilterSecurityInterceptor customFilterSecurityInterceptor() { FilterSecurityInterceptor fsi = new FilterSecurityInterceptor(); fsi.setAccessDecisionManager(customAccessDecisionManager); fsi.setSecurityMetadataSource(customSecurityMetadataSource); return fsi; } } |