1.权限模型RBAC模型
迄今为止最为普及的权限设计模型是 RBAC 模型, 基于角色的访问控制(Role-Based Access Control)
2.使用框架
- shiro
- spring security
3.spring security 如何使用
1. WebSecurityConfigurerAdapter
@Configuration
// 启用spring security
@EnableWebSecurity(debug = true)
//启用方法注解 例如 @PreAuthorize和@PostAuthorize
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder passwordEncoder() {
// 设置默认的加密方式
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
// 配置用户认证
@Bean
@Override
public UserDetailsService userDetailsService() {
return new UserDetailsServiceImpl();
}
// 认证模块
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService());
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
// 授权
@Override
public void configure(HttpSecurity http) throws Exception {
// 禁用csrf 防止csrf攻击
http.csrf().disable();
http
// 配置登录信息
.logout()
.logoutUrl("/logout").logoutSuccessUrl("/")
.and()
// 配置授权信息
.authorizeRequests()
.mvcMatchers( "/login","/login/**", "/assets/**")
.permitAll()
.anyRequest()
// 配置匿名登录
.authenticated()
.and()
// 配置oauth2 登录
.oauth2Login()
.authorizationEndpoint();
http.oauth2Client().authorizationCodeGrant();
}
// 静态资源配忽略
@Override
public void configure(WebSecurity web) throws Exception {
//oauth2 获取公钥配置
web.ignoring().mvcMatchers("/oauth/token_key", "/oauth/check_token");
}
}
HttpSecurity 日常的基本配置使用
方法 | 说明 |
---|---|
requestMatchers() | 为 SecurityFilterChain 提供URL拦截策略,具体还提供了 antMatcher 和 mvcMathcer |
openidLogin() | 用于基于 OpenId 的验证 |
headers() | 将安全标头添加到响应,比如说简单的 XSS 保护 |
cors() | 配置跨域资源共享( CORS ) |
sessionManagement() | 配置会话管理 |
portMapper() | 配置一个 PortMapper(HttpSecurity#(getSharedObject(class))) ,其他提供 SecurityConfigurer 的对象使用 PortMapper 从 HTTP 重定向到 HTTPS 或者从 HTTPS 重定向到 HTTP。默认情况下,Spring Security使用一个 PortMapperImpl 映射 HTTP 端口8080到 HTTPS 端口8443, HTTP 端口80到 HTTPS 端口443 |
jee() | 配置基于容器的预认证。 在这种情况下,认证由Servlet容器管理 |
x509() | 配置基于x509的预认证 rememberMe 配置“记住我”的验证 |
authorizeRequests() | 基于使用 HttpServletRequest 限制访问 |
requestCache() | 配置请求缓存 |
exceptionHandling() | 配置错误处理 |
securityContext() | 在 HttpServletRequests 之间的 SecurityContextHolder 上设置 SecurityContext 的管理。 当使 用 WebSecurityConfigurerAdapter 时,这将自动应用 |
servletApi() | 将 HttpServletRequest 方法与在其上找到的值集成到 SecurityContext 中。 当使用 WebSecurityConfigurerAdapter 时,这将自动应用 |
csrf() | 添加 CSRF 支持,使用 WebSecurityConfigurerAdapter 时,默认启用 |
logout() | 添加退出登录支持。当使用 WebSecurityConfigurerAdapter 时,这将自动应用。默认情况是,访问 URL”/ logout”,使HTTP Session无效来清除用户,清除已配置的任何#rememberMe()身份验证,清除 SecurityContextHolder ,然后重定向到 /login?success anonymous() 配置匿名用户的表示方法。 当与 WebSecurityConfigurerAdapter 结合使用时,这将自动应用。 默认 情况下,匿名用户将使用 org.springframework.security.authentication.AnonymousAuthenticationToken 表示,并包含 角色 ROLE_ANONYMOUS authenticationManager() 配置 AuthenticationManager |
authenticationProvider() | 添加 AuthenticationProvider |
formLogin() | 指定支持基于表单的身份验证。如果未指定 FormLoginConfigurer#loginPage(String) ,则将生成默 认登录页面 |
oauth2Login() | 根据外部OAuth 2.0或OpenID Connect 1.0提供程序配置身份验证 |
oauth2Client() | OAuth2.0 客户端相关的配置 |
oauth2ResourceServer() | OAuth2.0资源服务器相关的配置 |
requiresChannel() | 配置通道安全。为了使该配置有用,必须提供至少一个到所需信道的映射 |
httpBasic() | 配置 Http Basic 验证 |
addFilter() | 添加一个已经在内置过滤器注册表注册过的过滤器实例或者子类 |
addFilterBefore() | 在指定的Filter类之前添加过滤器 |
2.PasswordEncoder 密码校验器(主要用于)
@Bean
public PasswordEncoder passwordEncoder() {
// 设置默认的加密方式
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
3.UserDetailsService 用户信息接口
public interface UserDetailsService {
根据用户名定位用户。在实际实现中,搜索可能区分大小写,也可能不区分大小写,具体取决于实现实例的配置方式。
在这种情况下,返回的 <code>UserDetails<code> 对象的用户名可能与实际请求的用户名不同。
@param username 标识需要其数据的用户的用户名。
@return 完全填充的用户记录(从不 <code>null<code>)@throws UsernameNotFoundException
如果找不到用户或用户没有 GrantedAuthority
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}
根据用户名加载用户 UserDetails ,可能抛出用户不存在的异常 security 中 登录用UserDetailsService 去检索个人信息。
项目中的实践如下
@Service
public class UserDetailServiceImpl implements UserDetailsService {
@Autowired
private UserService userService;
@Autowired
private PermissionService permissionService;
@Override
@Transactional(readOnly = true)
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
// 查询用户信息
com.template.cloud.oauth.entity.User user = userService.loadUserByUserName(userName);
List<GrantedAuthority> grantedAuthorities =new ArrayList<>();
if (user != null) {
// 获取用户授权
Set<String> permissions = permissionService.loadPermissionByUserId(user.getId());
// 声明用户授权
if(CollUtil.isNotEmpty(permissions)){
permissions.forEach(permission -> {
if (StrUtil.isNotBlank(permission)) {
GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(permission);
grantedAuthorities.add(grantedAuthority);
}
});
}
// 由框架完成认证工作
return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), grantedAuthorities);
}else {
return null;
}
}
}
4.AuthenticationManager 认证管理器
主要处理认证请求的管理器
主要的实现如下
5.Authentication 认证信息
Spring Security中抽象了一个认证的概念接口 Authentication 。认证主体的认证信息、状态都
由 Authentication 来负责维护
6.spring security filter 顺序
FilterComparator() {
Step order = new Step(INITIAL_ORDER, ORDER_STEP);
put(ChannelProcessingFilter.class, order.next());
put(ConcurrentSessionFilter.class, order.next());
put(WebAsyncManagerIntegrationFilter.class, order.next());
put(SecurityContextPersistenceFilter.class, order.next());
put(HeaderWriterFilter.class, order.next());
put(CorsFilter.class, order.next());
put(CsrfFilter.class, order.next());
put(LogoutFilter.class, order.next());
filterToOrder.put(
"org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter",
order.next());
filterToOrder.put(
"org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationRequestFilter",
order.next());
put(X509AuthenticationFilter.class, order.next());
put(AbstractPreAuthenticatedProcessingFilter.class, order.next());
filterToOrder.put("org.springframework.security.cas.web.CasAuthenticationFilter",
order.next());
filterToOrder.put(
"org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter",
order.next());
filterToOrder.put(
"org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationFilter",
order.next());
put(UsernamePasswordAuthenticationFilter.class, order.next());
put(ConcurrentSessionFilter.class, order.next());
filterToOrder.put(
"org.springframework.security.openid.OpenIDAuthenticationFilter", order.next());
put(DefaultLoginPageGeneratingFilter.class, order.next());
put(DefaultLogoutPageGeneratingFilter.class, order.next());
put(ConcurrentSessionFilter.class, order.next());
put(DigestAuthenticationFilter.class, order.next());
filterToOrder.put(
"org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter", order.next());
put(BasicAuthenticationFilter.class, order.next());
put(RequestCacheAwareFilter.class, order.next());
put(SecurityContextHolderAwareRequestFilter.class, order.next());
put(JaasApiIntegrationFilter.class, order.next());
put(RememberMeAuthenticationFilter.class, order.next());
put(AnonymousAuthenticationFilter.class, order.next());
filterToOrder.put(
"org.springframework.security.oauth2.client.web.OAuth2AuthorizationCodeGrantFilter",
order.next());
put(SessionManagementFilter.class, order.next());
put(ExceptionTranslationFilter.class, order.next());
put(FilterSecurityInterceptor.class, order.next());
put(SwitchUserFilter.class, order.next());
}
每个filter 的作用
1、WebAsyncManagerIntegrationFilter:
提供了对securityContext和WebAsyncManager的集成,使其支持把SecurityContext设置基于ThreadLocal的SecurityContextHolder中,使controller中线程安全地获取到用户上下文认证信息。
2、SecurityContextPersistenceFilter
请求到来时,通过HttpSessionSecurityContextRepository接口从Session中读取SecurityContext,如果读取结果为null,则创建之。获得SecurityContext之后,会将其存入SecurityContextHolder,其中SecurityContextHolder默认是ThreadLocalSecurityContextHolderStrategy实例。
请求结束时清空SecurityContextHolder,并将SecurityContext保存到Session中。
3、HeaderWriterFilter
用来给http response添加一些Header,比如X-Frame-Options、X-XSS-Protection*、X-Content-Type-Options。
X-Frame-Options:防止某些重要网页被其他网站框架导入
X-XSS-Protection*:防止XSS攻击
X-Content-Security-Policy:这个响应头主要是用来定义页面可以加载哪些资源,减少XSS的发生
X-Content-Type-Options:互联网上的资源有各种类型,通常浏览器会根据响应头的Content-Type字段来分辨它们的类型。例如:text/html、text/css
4、CsrfFilter
防止csrf跨域攻击,伪造表单,要求表单POST提交时带有crsf令牌
5、LogoutFilter
对登出url的请求处理,执行登出操作
6、UsernamePasswordAuthenticationFilter
对登陆url的请求处理,校验用户账号密码,校验成功后执行以下操作:
a. (ConcurrentSessionStrategy)向框架特有的SessionRegistry添加用户和session信息,并管理策略执行用户多点登陆检查,做出对应的‘不予许登陆’或‘令旧会话失效’和‘允许登陆的操作’
b. 在SecurityContext存认证信息
c. 执行rememberme服务,添加cookies
d. 由eventpublisher发布认证事件
e. 结束filter链,登陆成功跳转,执行新一轮的filter链检查(这次时已登陆状态不用再登陆啦)
7、ConcurrentSessionFilter
根据当前sessionID检查SessionRegistry保存的session信息是否过期
过期:则执行登出操作(销毁旧过期session触发session事件从而删除SessionRegistry的信息)跳转到login操作尝试自动登陆,此时一般会由rememberme执行登陆,此时登出操作一般会把rememberme删除,登陆失败,跳转到登陆页,手动登陆
不过期:则刷新访问时间
不存在则跳过
8、RequestCacheAwareFilter
将request存到session中,用于缓存request请求,可以用于恢复被登录而打断的请求
此处从session中取出request,存储request是ExceptionTranslationFilter
9、SecurityContextHolderAwareRequestFilter
此过滤器对ServletRequest进行了一次包装,使得request具有更加丰富的API
10、RememberMeAuthenticationFilter
服务器重启后rememberme失效,默认保存在内存的和SessionRegistry一样需要重新配置
读取客户端的remember的cookies来实现自动登陆,在SecurityContext存认证信息
11、AnonymousAuthenticationFilter
前面都没有成功登陆则执行匿名登陆,在SecurityContext存认证信息
12、SessionManagementFilter
session固化保护-通过session-fixation-protection配置
session并发控制-通过concurrency-control配置 (这个主要在过过滤器6和7执行的)和session相关的过滤器,内部维护了一个SessionAuthenticationStrategy,两者组合使用,常用来防止session-fixation protection attack,以及限制同一用户开启多个会话的数量
与登录认证拦截时作用一样,持久化用户登录信息,可以保存到session中,也可以保存到cookie或者redis中。
13、ExceptionTranslationFilter
异常拦截,其处在Filter链后部分,只能拦截其后面的节点并且只处理AuthenticationException
与AccessDeniedException两个异常。AuthenticationException指的是未登录状态下访问受保护资源,
AccessDeniedException指的是登陆了但是由于权限不足(比如普通用户访问管理员界面)。
14、FilterSecurityInterceptor
这个filter用于授权验证。FilterSecurityInterceptor的工作流程引用一下,可以理解如下:
FilterSecurityInterceptor从SecurityContextHolder中获取Authentication对象,
然后比对用户拥有的权限和资源所需的权限。前者可以通过Authentication对象直接获得,
而后者则需要引入我们之前一直未提到过的两个类:SecurityMetadataSource,AccessDecisionManager。