转载于: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 自定义 登陆 权限验证的更多相关文章

  1. (二)spring Security 自定义登录页面与校验用户

    文章目录 配置 security 配置下 MVC 自定义登录页面 自定义一个登陆成功欢迎页面 效果图 小结: 使用 Spring Boot 的快速创建项目功能,勾选上本篇博客需要的功能:web,sec ...

  2. 登陆模块,这个是很重要的模块,有shiro和spring security专门的权限认证框架

    登陆模块,这个是很重要的模块,有shiro和spring security专门的权限认证框架

  3. Struts2 自定义拦截器实例—登陆权限验证

    实现一个登陆权限验证的功能 message.jsp: <body> message:${message } </body> login.jsp: <% request.g ...

  4. Spring Security 自定义登录认证(二)

    一.前言 本篇文章将讲述Spring Security自定义登录认证校验用户名.密码,自定义密码加密方式,以及在前后端分离的情况下认证失败或成功处理返回json格式数据 温馨小提示:Spring Se ...

  5. Spring Security 动态url权限控制(三)

    一.前言 本篇文章将讲述Spring Security 动态分配url权限,未登录权限控制,登录过后根据登录用户角色授予访问url权限 基本环境 spring-boot 2.1.8 mybatis-p ...

  6. spring security自定义指南

    序 本文主要研究一下几种自定义spring security的方式 主要方式 自定义UserDetailsService 自定义passwordEncoder 自定义filter 自定义Authent ...

  7. Spring Security实现RBAC权限管理

    Spring Security实现RBAC权限管理 一.简介 在企业应用中,认证和授权是非常重要的一部分内容,业界最出名的两个框架就是大名鼎鼎的 Shiro和Spring Security.由于Spr ...

  8. 解决Spring Security自定义filter重复执行问题

    今天做项目的时候,发现每次拦截器日志都会打两遍,很纳闷,怀疑是Filter被执行了两遍.结果debug之后发现还真是!记录一下这个神奇的BUG! 问题描述 项目中使用的是Spring-security ...

  9. Spring Security 自定义登录页面

    SpringMVC + Spring Security,自定义登录页面登录验证 学习参考:http://www.mkyong.com/spring-security/spring-security-f ...

随机推荐

  1. 在Visual C++ 6.0中为代码添加行号

    由如上代码可知Visual C++ 6.0是没有行号的(新手代码不要在意,重点是没有行号),在编译报错的时候会发现其会指出在第几行错了,如果没有代码行号将很难找到它 为解决这个问题可以安装插件给Vis ...

  2. python学习-9 pycharm的安装

    1.python 开发IDE :  pycharm.eclipse等等 安装: 百度搜索pycharm 就可以了,去官网下载专业版.(百度有各种破解方法)                    #不要 ...

  3. springMVC接受json类型数据

    springMVC接受json格式的数据很简单 使用@RequestBody 注解,标识从请求的body中取值 服务端示例代码 @RequestMapping(value = "/t4&qu ...

  4. dev gridview 视图层级

    表格对象继承的关系

  5. 关于如何查看 MySQL 信息、查看Oracle 版本

    方法一: 进入mysql cmd, mysql -u root status; 将显示当前mysql的version的各种信息. 方法二: 还是在mysql的cmd下,输入: select versi ...

  6. _stscanf_s (sscanf)正则表达式

    _stscanf_s (sscanf)正则表达式     {%[*] [width] [{h | l | I64 | L}]type  |  ' ' |  '\t' | '\n' | 非%符号}, 注 ...

  7. python numpy 删除array指定位置的元素

    如图:设计一个数组或者tuple,其中的元素是True或False,那么在False位置上的元素就会被删掉 索引的元素还可以是int型的数,这时候就代表,将原来的数组中指定位置的数放在当前的位置,且索 ...

  8. vue路径中的#号

    最近学习vue过程中,发现路径当中总是存在一个#号,比如这个: 这种情况是因为在入口js文件中,如果你不更改设置的话,vue会默认使用hash模式,该模式下回将路径格式化为 # 开头. 如果需要美化路 ...

  9. 5.1 Request 获取请求数据的几种方法

    //获取请求头和请求数据 //请求数据(1.通过超链接 2.通过表单) //获取请求数据的时候一般来说 都要先检查 再使用 public class RequestDemo2 extends Http ...

  10. opencv3.0中contrib模块的添加+实现SIFT/SURF算法

    平台:win10 x64 +VS 2015专业版 +opencv-3.x.+CMake+Anaconda3(python3.7.0) Issue说明:Opencv3.0版本已经发布了有一段时间,在这段 ...