Spring Security 自定义 登陆 权限验证
转载于: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
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
Spring Security 自定义 登陆 权限验证的更多相关文章
- (二)spring Security 自定义登录页面与校验用户
文章目录 配置 security 配置下 MVC 自定义登录页面 自定义一个登陆成功欢迎页面 效果图 小结: 使用 Spring Boot 的快速创建项目功能,勾选上本篇博客需要的功能:web,sec ...
- 登陆模块,这个是很重要的模块,有shiro和spring security专门的权限认证框架
登陆模块,这个是很重要的模块,有shiro和spring security专门的权限认证框架
- Struts2 自定义拦截器实例—登陆权限验证
实现一个登陆权限验证的功能 message.jsp: <body> message:${message } </body> login.jsp: <% request.g ...
- Spring Security 自定义登录认证(二)
一.前言 本篇文章将讲述Spring Security自定义登录认证校验用户名.密码,自定义密码加密方式,以及在前后端分离的情况下认证失败或成功处理返回json格式数据 温馨小提示:Spring Se ...
- Spring Security 动态url权限控制(三)
一.前言 本篇文章将讲述Spring Security 动态分配url权限,未登录权限控制,登录过后根据登录用户角色授予访问url权限 基本环境 spring-boot 2.1.8 mybatis-p ...
- spring security自定义指南
序 本文主要研究一下几种自定义spring security的方式 主要方式 自定义UserDetailsService 自定义passwordEncoder 自定义filter 自定义Authent ...
- Spring Security实现RBAC权限管理
Spring Security实现RBAC权限管理 一.简介 在企业应用中,认证和授权是非常重要的一部分内容,业界最出名的两个框架就是大名鼎鼎的 Shiro和Spring Security.由于Spr ...
- 解决Spring Security自定义filter重复执行问题
今天做项目的时候,发现每次拦截器日志都会打两遍,很纳闷,怀疑是Filter被执行了两遍.结果debug之后发现还真是!记录一下这个神奇的BUG! 问题描述 项目中使用的是Spring-security ...
- Spring Security 自定义登录页面
SpringMVC + Spring Security,自定义登录页面登录验证 学习参考:http://www.mkyong.com/spring-security/spring-security-f ...
随机推荐
- 在Visual C++ 6.0中为代码添加行号
由如上代码可知Visual C++ 6.0是没有行号的(新手代码不要在意,重点是没有行号),在编译报错的时候会发现其会指出在第几行错了,如果没有代码行号将很难找到它 为解决这个问题可以安装插件给Vis ...
- python学习-9 pycharm的安装
1.python 开发IDE : pycharm.eclipse等等 安装: 百度搜索pycharm 就可以了,去官网下载专业版.(百度有各种破解方法) #不要 ...
- springMVC接受json类型数据
springMVC接受json格式的数据很简单 使用@RequestBody 注解,标识从请求的body中取值 服务端示例代码 @RequestMapping(value = "/t4&qu ...
- dev gridview 视图层级
表格对象继承的关系
- 关于如何查看 MySQL 信息、查看Oracle 版本
方法一: 进入mysql cmd, mysql -u root status; 将显示当前mysql的version的各种信息. 方法二: 还是在mysql的cmd下,输入: select versi ...
- _stscanf_s (sscanf)正则表达式
_stscanf_s (sscanf)正则表达式 {%[*] [width] [{h | l | I64 | L}]type | ' ' | '\t' | '\n' | 非%符号}, 注 ...
- python numpy 删除array指定位置的元素
如图:设计一个数组或者tuple,其中的元素是True或False,那么在False位置上的元素就会被删掉 索引的元素还可以是int型的数,这时候就代表,将原来的数组中指定位置的数放在当前的位置,且索 ...
- vue路径中的#号
最近学习vue过程中,发现路径当中总是存在一个#号,比如这个: 这种情况是因为在入口js文件中,如果你不更改设置的话,vue会默认使用hash模式,该模式下回将路径格式化为 # 开头. 如果需要美化路 ...
- 5.1 Request 获取请求数据的几种方法
//获取请求头和请求数据 //请求数据(1.通过超链接 2.通过表单) //获取请求数据的时候一般来说 都要先检查 再使用 public class RequestDemo2 extends Http ...
- opencv3.0中contrib模块的添加+实现SIFT/SURF算法
平台:win10 x64 +VS 2015专业版 +opencv-3.x.+CMake+Anaconda3(python3.7.0) Issue说明:Opencv3.0版本已经发布了有一段时间,在这段 ...