Тринадцатый анализ исходного кода Spring Security: управление разрешениями на основе выражений Spring Security

задняя часть GitHub Spring Безопасность

Spring Security — это инфраструктура безопасности, которая может предоставлять решения для декларативного контроля доступа к безопасности для систем корпоративных приложений на основе Spring. Он предоставляет набор bean-компонентов, которые можно настроить в контексте приложения Spring, в полной мере используя функции Spring IoC, DI (инверсия управления, DI: внедрение зависимостей) и AOP (аспектно-ориентированное программирование) для предоставления прикладным системам декларативного безопасного доступа. возможности управления уменьшают усилия по написанию большого количества повторяющегося кода для средств управления безопасностью корпоративной системы.

предисловие

spring security 3.0уже доступноspring elВыражения для управления авторизацией, позволяющие использовать сложную логическую логику в выражениях для управления правами доступа.

общие выражения

Базовым классом для доступных объектов выражений Spring Security является SecurityExpressionRoot.

выражение описывать
hasRole([role]) Возвращает true, если у пользователя есть указанная роль (Spring securityПо умолчанию он будет иметьROLE_префикс), удалить ссылкиRemove the ROLE_
hasAnyRole([role1,role2]) Возвращает true, если у пользователя есть какая-либо из указанных ролей
hasAuthority([authority]) ЭквивалентноhasRole, но не сROLE_префикс
hasAnyAuthority([auth1,auth2]) ЭквивалентноhasAnyRole
permitAll всегда возвращает истину
denyAll всегда возвращает ложь
anonymous Текущий пользовательanonymousвозвращает истину, когда
rememberMe Нынешний воинrememberMeпользователь возвращает истину
authentication текущий авторизованный пользовательauthenticationобъект
fullAuthenticated Текущий пользователь неanonymousни одинrememberMeВозвращает true, когда пользователь
hasIpAddress('192.168.1.0/24')) Возвращает true, если IP-адрес, отправленный запросом, совпадает

Часть кода:

......
private String defaultRolePrefix = "ROLE_"; //ROLE_前缀

	/** Allows "permitAll" expression */
	public final boolean permitAll = true; //全部true

	/** Allows "denyAll" expression */
	public final boolean denyAll = false; //全部false
public final boolean permitAll() {
		return true;
	}

	public final boolean denyAll() {
		return false;
	}

	public final boolean isAnonymous() {
		//是否是anonymous
		return trustResolver.isAnonymous(authentication);
	}

	public final boolean isRememberMe() {
		//是否是rememberme
		return trustResolver.isRememberMe(authentication);
	}
......

Безопасные выражения URL

onfig.antMatchers("/person/*").access("hasRole('ADMIN') or hasRole('USER')")
                .anyRequest().authenticated();

Здесь мы определяем приложение/person/*Диапазон URL-адресов, предназначенных только для владельцевADMINилиUSERРазрешения действительны для пользователей.

Ссылки на bean-компоненты в безопасных веб-выражениях

config.antMatchers("/person/*").access("hasRole('ADMIN') or hasRole('USER')")
                .antMatchers("/person/{id}").access("@rbacService.checkUserId(authentication,#id)")
                .anyRequest()
                .access("@rbacService.hasPermission(request,authentication)");
RbacServiceImpl
@Component("rbacService")
@Slf4j
public class RbacServiceImpl implements RbacService {
    /**
     * uri匹配工具
     */
    private AntPathMatcher antPathMatcher = new AntPathMatcher();

    @Override
    public boolean hasPermission(HttpServletRequest request, Authentication authentication) {
        log.info("【RbacServiceImpl】  --hasPermission={}", authentication.getPrincipal());
        Object principal = authentication.getPrincipal();

        boolean hasPermission = false;
        //有可能是匿名的anonymous
        if (principal instanceof SysUser) {
            //admin永远放回true
            if (StringUtils.equals("admin", ((SysUser) principal).getUsername())) {
                hasPermission = true;
            } else {
                //读取用户所拥有权限所有的URL 在这里全部返回true
                Set<String> urls = new HashSet<>();

                for (String url : urls) {
                    if (antPathMatcher.match(url, request.getRequestURI())) {
                        hasPermission = true;
                        break;
                    }
                }
            }
        }
        return hasPermission;
    }

	  public boolean checkUserId(Authentication authentication, int id) {
        return true;
    }
}

Эффект следующий:

https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2018/1/30/16147b3f89291c64~tplv-t2oaga2asx-image.image
https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2018/1/30/16147b3f89291c64~tplv-t2oaga2asx-image.image

Безопасное выражение метода

Контроль доступа на уровне метода более сложен.Spring SecurityПредоставляются четыре аннотации, а именно@PreAuthorize , @PreFilter , @PostAuthorizeа также@PostFilter

Аннотировать методом

  1. Включить настройку аннотаций на уровне метода
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MerryyouSecurityConfig extends WebSecurityConfigurerAdapter {
  1. Настройте соответствующий bean-компонент
 @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

    @Bean
    @ConditionalOnMissingBean(PasswordEncoder.class)
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
  1. Используйте аннотации к методам
 /**
     * 查询所有人员
     */
    @PreAuthorize("hasRole('ADMIN')")
    @ApiOperation(value = "获得person列表", notes = "")
    @GetMapping(value = "/persons")
    public List<Person> getPersons() {
        return personService.findAll();
    }
PreAuthorize

Аннотация @PreAuthorize подходит для проверки авторизации перед входом в метод

@PreAuthorize("hasRole('ADMIN')")
    List<Person> findAll();
PostAuthorize

@PostAuthorize выполняет проверку авторизации после выполнения метода, что подходит для проверки авторизации с возвращаемым значением.Spring ELПредоставляет возвращаемый объект, чтобы иметь возможность получить возвращенный объект на языке выражений.returnObject.

@PostAuthorize("returnObject.name == authentication.name")
    Person findOne(Integer id);
Предварительная авторизация фильтров по параметрам
//当有多个对象是使用filterTarget进行标注
@PreFilter(filterTarget="ids", value="filterObject%2==0")
   public void delete(List<Integer> ids, List<String> usernames) {
      ...

   }
PostFilter фильтрует возвращаемые результаты
 @PreAuthorize("hasRole('ADMIN')")
    @PostFilter("filterObject.name == authentication.name")
    List<Person> findAll();

Эффект следующий:

https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/security/spring-security-el02.gif
https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/security/spring-security-el02.gif

загрузка кода

Скачать с моего гитхаба,GitHub.com/Longfeizhen…

Категории