Spring Security基于数据库配置权限(角色,路径)
来源:互联网 发布:alias是什么软件 编辑:程序博客网 时间:2024/05/29 10:10
Spring Security基于数据库配置权限(角色,路径)
传统的后台管理系统,在权限处理上通常5个表:用户表,角色表,资源表,用户角色关联表,角色资源关联表。现在为了避免重复造轮子,自己写拦截处理,我们可以使用Spring Security来做权限控制。
Spring Security官方推荐通过配置来实现角色和资源的对应,这样的问题是假如需要线上配置角色与资源对应就不行了,所以下面讲讲如何基于数据库中存储角色,资源,用户 来使用Spring Security做权限控制。
1.首先是数据准备
创建权限相关的五张表和对应的实体类。以及相关的查询实现等。
2.配置类SecurityConfiguration
只要使用spring security都要有这样一个配置类(如果是类配置的话),继承WebSecurityConfigurerAdapter
主要实现两个方法configure(AuthenticationManagerBuilder auth)
和
configure(HttpSecurity http)
AuthenticationManagerBuilder
主要配置身份认证来源,也就是用户及其角色。HttpSecurity
主要配置路径,也就是资源的访问权限(是否需要认证,需要什么角色等)。
2.1 configure(AuthenticationManagerBuilder auth)
相关
该方法本身只需要设置一个身份认证来源,所以我们需要先写个方法来创建该来源
@Bean public BCryptPasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); //创建密码加密对象 } /** * @return 封装身份认证提供者 */ @Bean public DaoAuthenticationProvider authenticationProvider() { DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider(); authenticationProvider.setUserDetailsService(customUserService); //自定义的用户和角色数据提供者 authenticationProvider.setPasswordEncoder(passwordEncoder()); //设置密码加密对象 return authenticationProvider; } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(authenticationProvider()); //设置身份认证提供者 }
自定义的类需要实现UserDetailsService
实现接口中的方法
UserDetails loadUserByUsername(String var1) throws UsernameNotFoundException;
UserDetails中包含用户的用户名,密码,角色等信息。所以需要自己创建一个类实现UserDetails
,这样方便我们赋值我们查到的角色集合
比如创建一个UserPrincipal
public class UserPrincipal implements UserDetails { private User user; private List<String> roleCodes; UserPrincipal(User user,List<String> roleCodes){ this.user = user; this.roleCodes = roleCodes; } /** * 设置用户角色集合 */ @Override public Collection<? extends GrantedAuthority> getAuthorities() { return roleCodes.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList()); } @Override public String getPassword() { return user.getPassword(); } @Override public String getUsername() { return user.getUsername(); } ......}
CustomUserService
提供用户和对应的角色
public class CustomUserService implements UserDetailsService { @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userRepository.findByUsername(username); //根据用户名查询用户 if (user == null) { throw new UsernameNotFoundException("can not found username " + username); } return new UserPrincipal(user,getRoleCodes(user)); } private List<String> getRoleCodes(User user){ return ....//根据用户查询该用户拥有的角色编号集合 }}
这样就完成了对用户和角色的查询,接下来就是配置路径(资源)和角色映射了
2.2 configure(HttpSecurity http)
相关
主要就配置登陆路径,错误页面路径,后置处理程序等。
@Override protected void configure(HttpSecurity http) throws Exception { http.formLogin().loginPage("/login").defaultSuccessUrl("/",true) .and() .exceptionHandling().accessDeniedPage("/error") .and() .csrf().disable() .authorizeRequests().anyRequest().authenticated() .withObjectPostProcessor(postProcessor);//设置后置处理程序对象 }
加上前面的代码,配置类基本就完成了,记得加上@Configuration注解。接下来就是利用角色对路径进行判断了,这部分处理都封装在postProcessor
中的 FilterSecurityInterceptor
中。
3.权限处理配置 postProcessor
现在需要定义一个类来实现 ObjectPostProcessor<FilterSecurityInterceptor>
public class CustomPostProcessor implements ObjectPostProcessor<FilterSecurityInterceptor> { @Override public <T extends FilterSecurityInterceptor> T postProcess(T fsi) { fsi.setAccessDecisionManager(accessDecisionManager); //权限决策处理类 fsi.setSecurityMetadataSource(filterSecurityMetadataSource); //路径(资源)拦截处理 return fsi; }}
3.1 路径拦截处理类
filterSecurityMetadataSource
需要实现 FilterInvocationSecurityMetadataSource
接口,Collection<ConfigAttribute> getAttributes(Object object)
会返回改路径所需的角色集合到权限决策处理类中供其使用.
public class CustomFilterSecurityMetadataSource implements FilterInvocationSecurityMetadataSource{ @Override public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException { FilterInvocation fi = (FilterInvocation) object; //当前请求对象 if (isMatcherAllowedRequest(fi)) return null ; //return null 表示允许访问,不做拦截 List<ConfigAttribute> configAttributes = getMatcherConfigAttribute(fi.getRequestUrl()); return configAttributes.size() > 0 ? configAttributes : deniedRequest(); //返回当前路径所需角色,如果没有则拒绝访问 } @Override public Collection<ConfigAttribute> getAllConfigAttributes() { return null; } @Override public boolean supports(Class< ? > aClass) { return FilterInvocation.class.isAssignableFrom(aClass); } /** * 获取当前路径所需要的角色 * @param url 当前路径 * @return 所需角色集合 */ private List<ConfigAttribute> getMatcherConfigAttribute(String url){ return roleResourceRepository.findByResource_ResUrl(url).stream() .map(roles -> new SecurityConfig(roles.getRole().getRoleCode())) .collect(Collectors.toList()); } /** * 判断当前请求是否在允许请求的范围内 * @param fi 当前请求 * @return 是否在范围中 */ private boolean isMatcherAllowedRequest(FilterInvocation fi){ return allowedRequest().stream().map(AntPathRequestMatcher::new) .filter(requestMatcher -> requestMatcher.matches(fi.getHttpRequest())) .toArray().length > 0; } /** * @return 定义允许请求的列表 */ private List<String> allowedRequest(){ return Arrays.asList("/login","/css/**","/fonts/**","/js/**","/scss/**","/img/**"); } /** * @return 默认拒绝访问配置 */ private List<ConfigAttribute> deniedRequest(){ return Collections.singletonList(new SecurityConfig("ROLE_DENIED")); }}
3.2 权限决策处理
accessDecisionManager
需要实现 AccessDecisionManager
接口。实现方法decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)
来做权限决策
authentication
可获取当前用户拥有的角色集合configAttributes
路径拦截处理中查询到的,能访问当前路径的角色集合
public class CustomAccessDecisionManager implements AccessDecisionManager { @Override public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException { if(authentication == null){ throw new AccessDeniedException("permission denied"); } //当前用户拥有的角色集合 List<String> roleCodes = authentication.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList()); //访问路径所需要的角色集合 List<String> configRoleCodes = configAttributes.stream().map(ConfigAttribute::getAttribute).collect(Collectors.toList()); for (String roleCode : roleCodes){ if(configRoleCodes.contains(roleCode)){ return; } } throw new AccessDeniedException("permission denied"); }}
这样就完成了基于数据库存储的Spring Security权限控制实现。
- Spring Security基于数据库配置权限(角色,路径)
- Spring Security 基于数据库的权限管理配置
- 简单的基于spring security的基于角色验证的权限案例
- spring security 采用角色控制访问权限
- Spring security 用户,角色,权限,资源
- spring security使用数据库获取资源、角色和权限保护web应用
- Spring Boot集成Security使用数据库用户角色权限用户名问题
- Spring Boot集成Security使用数据库用户角色权限ROLE_问题
- spring security 3 角色继承配置
- spring security基于数据库的安全认证 配置
- Spring安全权限管理(Spring Security的配置使用)
- Spring安全权限管理(Spring Security的配置使用)
- spring security的配置(连数据库)
- 基于角色的权限管理数据库设计(RBAC)
- 基于角色的权限管理数据库设计(RBAC)
- spring security基于方法的权限控制
- 基于角色的权限设计 - 数据库
- Spring Security 4 基于角色的登录例子(带源码)
- 软件企业如何实施CMM?
- c++设计模式之状态模式
- 蓝桥杯篇2
- Java NIO流
- 使派生类构造函数变得简洁优雅
- Spring Security基于数据库配置权限(角色,路径)
- 时间服务器中,适用于国内的 NTP 服务器地址,可用于时间同步或 Android 加速 GPS 定位
- 【线程的同步与互斥 (互斥量 条件变量 信号量)】生产者与消费者模型
- 全面解析Linux 内核 3.10.x
- 带你5分钟搞懂 block 回调
- Tensorflow中使用TFRecords高效读取数据--结合NLP数据实践
- 实现SpringMVC中使用@Responsebody注解返回任意POJO对象转换成JSON
- 写于面试前的一段话
- 全面解析Linux 内核 3.10.x