转载于: 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);
这个方法是来获取资源权限 , 可以重写
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
来源: http://www.bubuko.com/infodetail-3341728.html