spring security 实现自定义url鉴权

package com.liuyanzhao.sens.config.security;
import com.liuyanzhao.sens.common.utils.SecurityUtil;
import com.liuyanzhao.sens.config.security.jwt.AuthenticationFailHandler;
import com.liuyanzhao.sens.config.security.jwt.AuthenticationSuccessHandler;
import com.liuyanzhao.sens.config.security.jwt.JWTAuthenticationFilter;
import com.liuyanzhao.sens.config.security.jwt.RestAccessDeniedHandler;
import com.liuyanzhao.sens.config.security.permission.MyFilterSecurityInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
/**

  • Security 核心配置类
  • 开启注解控制权限至Controller
  • @author 言曌
    */
    @Slf4j
    @Configuration
    @EnableGlobalMethodSecurity(prePostEnabled=true)
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private IgnoredUrlsProperties ignoredUrlsProperties;
    @Autowired
    private UserDetailsServiceImpl userDetailsService;
    @Autowired
    private AuthenticationSuccessHandler successHandler;
    @Autowired
    private AuthenticationFailHandler failHandler;
    @Autowired
    private RestAccessDeniedHandler accessDeniedHandler;
    @Autowired
    private MyFilterSecurityInterceptor myFilterSecurityInterceptor;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private SecurityUtil securityUtil;
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
    ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry registry = http
    .authorizeRequests();
    //除配置文件忽略路径其它所有请求都需经过认证和授权
    for(String url:ignoredUrlsProperties.getUrls()){
    registry.antMatchers(url).permitAll();
    }
    registry.and()
    //表单登录方式
    .formLogin()
    .loginPage("/sens/common/needLogin")
    //登录请求url
    .loginProcessingUrl("/sens/login")
    .permitAll()
    //成功处理类
    .successHandler(successHandler)
    //失败
    .failureHandler(failHandler)
    .and()
    //允许网页iframe
    .headers().frameOptions().disable()
    .and()
    .logout()
    .permitAll()
    .and()
    .authorizeRequests()
    //任何请求
    .anyRequest()
    //需要身份认证
    .authenticated()
    .and()
    //关闭跨站请求防护
    .csrf().disable()
    //前后端分离采用JWT 不需要session
    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
    .and()
    //自定义权限拒绝处理类
    .exceptionHandling().accessDeniedHandler(accessDeniedHandler)
    .and() //添加自定义权限过滤器
    .addFilterBefore(myFilterSecurityInterceptor, FilterSecurityInterceptor.class);
    }
    }
    addFilterBefore 作用就是当执行权限验证前执行,我们需要在这之前判断即可。

2.自定义拦截器

MyFilterSecurityInterceptor.java

package com.liuyanzhao.sens.config.security.permission;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.SecurityMetadataSource;
import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
import org.springframework.security.access.intercept.InterceptorStatusToken;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import java.io.IOException;
/**

  • 权限管理拦截器
  • 监控用户行为
  • @author 言曌
    */
    @Slf4j
    @Component
    public class MyFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {
    @Autowired
    private FilterInvocationSecurityMetadataSource securityMetadataSource;
    @Autowired
    public void setMyAccessDecisionManager(MyAccessDecisionManager myAccessDecisionManager) {
    super.setAccessDecisionManager(myAccessDecisionManager);
    }
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    FilterInvocation fi = new FilterInvocation(request, response, chain);
    invoke(fi);
    }
    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 void destroy() {
    }
    @Override
    public Class<?> getSecureObjectClass() {
    return FilterInvocation.class;
    }
    @Override
    public SecurityMetadataSource obtainSecurityMetadataSource() {
    return this.securityMetadataSource;
    }
    }

3.自定义权限资源管理器

MySecurityMetadataSource.java

package com.liuyanzhao.sens.config.security.permission;
import com.liuyanzhao.sens.common.constant.CommonConstant;
import com.liuyanzhao.sens.modules.base.entity.Permission;
import com.liuyanzhao.sens.modules.base.service.PermissionService;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import java.util.*;
/**

  • 权限资源管理器
  • 为权限决断器提供支持
  • @author 言曌
    /
    @Slf4j
    @Component
    public class MySecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
    @Autowired
    private PermissionService permissionService;
    private Map<String, Collection> map = null;
    /
    *
    • 加载权限表中所有操作请求权限
      /
      public void loadResourceDefine() {
      map = new HashMap<>(16);
      Collection configAttributes;
      ConfigAttribute cfg;
      // 获取启用的权限操作请求
      List permissions = permissionService.findByTypeAndStatusOrderBySortOrder(CommonConstant.PERMISSION_OPERATION, CommonConstant.STATUS_NORMAL);
      for (Permission permission : permissions) {
      if (StrUtil.isNotBlank(permission.getTitle()) && StrUtil.isNotBlank(permission.getPath())) {
      configAttributes = new ArrayList<>();
      cfg = new SecurityConfig(permission.getTitle());
      //作为MyAccessDecisionManager类的decide的第三个参数
      configAttributes.add(cfg);
      //用权限的path作为map的key,用ConfigAttribute的集合作为value
      map.put(permission.getPath(), configAttributes);
      }
      }
      }
      /
      *
    • 判定用户请求的url是否在权限表中
    • 如果在权限表中,则返回给decide方法,用来判定用户是否有此权限
    • 如果不在权限表中则放行
    • @param o
    • @return
    • @throws IllegalArgumentException
      */
      @Override
      public Collection getAttributes(Object o) throws IllegalArgumentException {
      if (map == null) {
      loadResourceDefine();
      }
      //Object中包含用户请求request
      String url = ((FilterInvocation) o).getRequestUrl();
      PathMatcher pathMatcher = new AntPathMatcher();
      Iterator iterator = map.keySet().iterator();
      while (iterator.hasNext()) {
      String resURL = iterator.next();
      if (StrUtil.isNotBlank(resURL) && pathMatcher.match(resURL, url)) {
      return map.get(resURL);
      }
      }
      return null;
      }
      @Override
      public Collection getAllConfigAttributes() {
      return null;
      }
      @Override
      public boolean supports(Class<?> aClass) {
      return true;
      }
      }

4.自定义角色决断器

MyAccessDecisionManager.java

package com.liuyanzhao.sens.config.security.permission;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Component;
import java.util.Collection;
import java.util.Iterator;
/**

  • 权限管理决断器
  • 判断用户拥有的权限或角色是否有资源访问权限
  • @author 言曌
    */
    @Slf4j
    @Component
    public class MyAccessDecisionManager implements AccessDecisionManager {
    @Override
    public void decide(Authentication authentication, Object o, Collection configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
    if(configAttributes==null){
    return;
    }
    Iterator iterator = configAttributes.iterator();
    while (iterator.hasNext()){
    ConfigAttribute c = iterator.next();
    String needPerm = c.getAttribute();
    for(GrantedAuthority ga : authentication.getAuthorities()) {
    // 匹配用户拥有的ga 和 系统中的needPerm
    if(needPerm.trim().equals(ga.getAuthority())) {
    return;
    }
    }
    }
    throw new AccessDeniedException(“抱歉,您没有访问权限”);
    }
    @Override
    public boolean supports(ConfigAttribute configAttribute) {
    return true;
    }
    @Override
    public boolean supports(Class<?> aClass) {
    return true;
    }
    }

转自-https://liuyanzhao.com/9617.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值