转载于:https://www.jianshu.com/p/6b8fb59b614b
项目简介
基于Spring Cloud 的项目,Spring Cloud是在Spring Boot上搭建的所以按照Spring Boot的方式来写
Spring Security 配置
继承 WebSecurityConfigurerAdapter
,重写configure(HttpSecurity http)
配置相关权限以及重写拦截器
http.authorizeRequests() .antMatchers("/auth/**").permitAll() .anyRequest().authenticated().and() //证书 认证 自动登陆 .addFilterBefore(authTokenFilter, UsernamePasswordAuthenticationFilter.class) //登陆以及权限控制Filter ...... ;
自定义UsernamePasswordAuthenticationFilter
自定义 UsernamePasswordAuthenticationFilter 实现自动登陆
创建Authentication 模拟登陆
Authentication authentication = new UsernamePasswordAuthenticationToken(auth, token); SecurityContextHolder.getContext().setAuthentication(authentication);;
自定义FilterSecurityInterceptor
Spring Security 是通过这个过滤器来实现 Http资源安全过滤的。
获取资源权限
FilterSecurityInterceptor继承自 AbstractSecurityInterceptor ,源码中的其中beforeInvocation方法的一段代码是:
Collection<ConfigAttribute> attributes = this.obtainSecurityMetadataSource() .getAttributes(object);
这个方法是来获取资源权限 ,可以重写
这个对象中可以获取到request, response等内置对象,可以通过一下代码来匹配
SecurityMetadataSource obtainSecurityMetadataSource(){}
方法来实现,传入一个FilterInvocation对象,返回一个Collection<ConfigAttribute>对象。这个对象中可以获取到request, response等内置对象,可以通过一下代码来匹配
RequestMatcher requestMatcher = new AntPathRequestMatcher("/manager/**"); if(requestMatcher.matches(request)){ return RESOURCE } ConfigAttribute 可以通过new SecurityConfig((String)input) 来创建
编写认证提供者
重写 AuthenticationManager 实现,用户登陆可以放这里面
Authentication authenticate(Authentication authentication) throws AuthenticationException;
用来生成Authentication, 原始的够用的话直接注入设置就好。
用户是否有获取资源权限
AbstructSecurityIntercepter 中的一下方法来判断用户权限是否可以拥有该资源
this.accessDecisionManager.decide(authenticated, object, attributes);
为了达到自定义控制的目的,我们需要实现AccessDecisionManager接口,来重写这个方法,如果判断不通过 decide方法可以抛出AccessDeniedException,来阻止用户访问
/** * 判断用户是否有访问资源权限 * @param authentication 用户Auth * @param object FilterInvocation对象 * @param configAttributes 资源所需权限 * @throws AccessDeniedException 无权限Exception * @throws InsufficientAuthenticationException */ public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException { if(access){ //允许通过 return; } //不允许角色访问 throw new AccessDeniedException("NO ALLOW"); }
JAVA 源码片
WebSecurityConfig
@Configuration public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private AuthTokenFilter authTokenFilter; @Autowired private ApiPermissionSecurityFilter securityFilter; protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/auth/**").permitAll() .anyRequest().authenticated().and() //证书 认证 自动登陆 .addFilterBefore(authTokenFilter, UsernamePasswordAuthenticationFilter.class) //登陆以及权限控制Filter .addFilterBefore(securityFilter, FilterSecurityInterceptor.class) .csrf().disable() //基于Token 不需要Session .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) ; } }
AuthTokenFilter (自定义UsernamePasswordAuthenticationFilter)
@Component public class AuthTokenFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String auth = request.getHeader("Authorization"); //用户登陆,暂不设置权限 Token token = new Token(auth, null); Authentication authentication = new UsernamePasswordAuthenticationToken(auth, token); SecurityContextHolder.getContext().setAuthentication(authentication); filterChain.doFilter(request, response); } }
ApiPermissionSecurityFilter
@Component public class ApiPermissionSecurityFilter extends AbstractSecurityInterceptor implements Filter { @Autowired private ApiInvocationSecurityMetadataSourceService apiInvocationSecurityMetadataSourceService; @Autowired private ApiAccessDecisionManager apiAccessDecisionManager; @Autowired private AuthenticationManager authenticationManager; @PostConstruct public void init(){ super.setAuthenticationManager(authenticationManager); super.setAccessDecisionManager(apiAccessDecisionManager); } public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException{ FilterInvocation fi = new FilterInvocation( request, response, chain ); invoke(fi); } public Class<? extends Object> getSecureObjectClass(){ return FilterInvocation.class; } public void invoke( FilterInvocation fi ) throws IOException, ServletException{ InterceptorStatusToken token = super.beforeInvocation(fi); try{ fi.getChain().doFilter(fi.getRequest(), fi.getResponse()); }finally{ super.afterInvocation(token, null); } } @Override public SecurityMetadataSource obtainSecurityMetadataSource(){ return this.apiInvocationSecurityMetadataSourceService; } public void destroy(){ } public void init( FilterConfig filterconfig ) throws ServletException{ } }
ApiInvocationSecurityMetadataSourceService
/** * 资源-权限控制对象 * Created by liang on 2017/3/17. */ @Component public class ApiInvocationSecurityMetadataSourceService implements FilterInvocationSecurityMetadataSource { //缓存 英文名-权限 private static LoadingCache<String, Collection<ConfigAttribute>> permitMap = null; //缓存 英文名-ODCINFO信息对象 private static LoadingCache<String, OdcInfo> odcInfoMap = null; @PostConstruct private void init() { //资源启动时初始化 资源和角色权限 //缓存 英文名-权限 初始化 //缓存 英文名-ODCINFO } @Override public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException { FilterInvocation filterInvocation = (FilterInvocation) object; //TODO 干你想干事情,下面是获取路径所具有的资源 return permitMap.get(getHttpRequest().getRequestURI()); } @Override public Collection<ConfigAttribute> getAllConfigAttributes() { return new ArrayList<ConfigAttribute>(); } @Override public boolean supports(Class<?> aClass) { //很重要,不然不起作用 return true; } }
ApiAccessDecisionManager
@Component public class ApiAccessDecisionManager implements AccessDecisionManager { /** * 判断用户是否有访问资源权限 * @param authentication 用户Auth * @param object FilterInvocation对象 * @param configAttributes 资源所需权限 * @throws AccessDeniedException 无权限Exception */ public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException { if(access){ //允许通过 return; } //不允许角色访问 throw new AccessDeniedException("NO ALLOW"); } public boolean supports( ConfigAttribute attribute ){ return true; } public boolean supports(Class<?> clazz){ return true; } }
作者:libertinus
链接:https://www.jianshu.com/p/6b8fb59b614b
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。