249.Spring Boot+Spring Security:基于URL动态权限:扩展access()的SpEL表达式

Posted SpringBoot

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了249.Spring Boot+Spring Security:基于URL动态权限:扩展access()的SpEL表达式相关的知识,希望对你有一定的参考价值。

说明

(1)JDK版本:1.8

(2)Spring Boot 2.0.6

(3)Spring Security 5.0.9

(4)Spring Data JPA 2.0.11.RELEASE

(5)hibernate5.2.17.Final

(6)mysqlDriver 5.1.47

(7)MySQL 8.0.12

 

需求缘起

       本节通过扩展access()的SpEL表达式实现URL动态权限。

 

编码思路

       通过扩展SpEL表达式主要在配置具体的类和实现的方法,如下示例

.access("@authService.canAccess(request,authentication)");

       其中authService是一个类,canAccess是其中的方法:

@Component
public class AuthService {
    public boolean canAccess(HttpServletRequest request, Authentication authentication) {
        //在这里编写校验代码…
        return true;
    }
}

 

一、扩展access()的SpEL表达式

1.1 编写权限校验方法

       编写类AuthService:

package com.kfit.config;

import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Component;

import com.kfit.permission.service.PermissionService;

@Component
public class AuthService {

    @Autowired
    private PermissionService permissionService;

    /**
     * 1/ 判断是否已经登录了.
     * 当未登录的时候
     * principal = anonymousUser
     * authentication= AnonymousAuthenticationToken
     * 当登录之后
     * principal = userdetails.User
     * authentication = UsernamePasswordAuthenticationToken
     * 
     * 
     * @param request
     * @param authentication [AnonymousAuthenticationToken|UsernamePasswordAuthenticationToken]
     * @return
     */

    public boolean canAccess(HttpServletRequest request,Authentication authentication) {

        System.out.println("AuthService.canAccess()");
        boolean b = false;
        System.out.println(authentication);

        //1/ 判断是否已经登录了,anonymousUser|userdetails.User
        Object principal = authentication.getPrincipal();
        if(principal == null || "anonymousUser".equals(principal)) {
            return b;
        }

        //这里可以单独把AnonymousAuthenticationToken拿出来校验,也可以将放到roles统一校验,其role为ROLE_ANONYMOUS
        if(authentication instanceof AnonymousAuthenticationToken){
            //check if this uri can be access by anonymous
            //return
        }

        Map<String,Collection<ConfigAttribute>> map =  permissionService.getPermissionMap();

        //String uri = request.getRequestURI();
        //这种获取方式不好,不支持/user/**的匹配方式。
        //Collection<ConfigAttribute> configAttributes = map.get(uri);

        Collection<ConfigAttribute> configAttributes = null;
        String resUrl;
        //URL规则匹配.
        AntPathRequestMatcher matcher;
        for(Iterator<String> it  = map.keySet().iterator();it.hasNext();) {
            resUrl = it.next();
            matcher = new AntPathRequestMatcher(resUrl);
            if(matcher.matches(request)) {
                configAttributes =  map.get(resUrl);
                break;
            }
        }


        if(configAttributes == null || configAttributes.size() ==0) {
            return b;
        }

        ConfigAttribute cfa  = null;
        String needRole = null;
        for(Iterator<ConfigAttribute> it = configAttributes.iterator();it.hasNext();) {
            cfa = it.next();
            needRole = cfa.getAttribute();
            for(GrantedAuthority grantedAuthority:authentication.getAuthorities()) {
                if(needRole.equals(grantedAuthority.getAuthority())) {
                    System.out.println("needRole = "+needRole);
                    b = true;
                    break;
                }
            }
        }
        return b;
    }

}    

 

1.2 配置WebSecurityConfig

       在WebSecurityConfig中添加access配置:

    @Override
    protected void configure(HttpSecurity http) throws Exception {  
        http.authorizeRequests() // 定义哪些URL需要被保护、哪些不需要被保护
            .antMatchers("/login").permitAll()// 设置所有人都可以访问登录页面
            .antMatchers("/","/index").permitAll()
            .antMatchers("/test/**","/test1/**").permitAll()
            .antMatchers("/res/**/*.{js,html}").permitAll()
            .anyRequest().access("@authService.canAccess(request,authentication)")
            //.anyRequest().authenticated()  // 任何请求,登录后可以访问
            .and()
            .formLogin().loginPage("/login")
            ;

    }

 

1.3 去掉注解@PreAuthorize

       对于HelloController的注解@PreAuthorize的注解可以去掉了:

   

     @GetMapping("/helloAdmin")
    //@PreAuthorize("hasAnyRole('admin')")
    public String helloAdmin() {       
        return "Hello,admin";
    }

    @GetMapping("/helloUser")
    //@PreAuthorize("hasAnyRole('admin','normal')")    
    public String helloUser() {       
        return "Hello,user";
    }

       到这里就可以测试下效果了,和之前的结果应该是一样的。

历史文章

















我就是我,是颜色不一样的烟火。
我就是我,是与众不同的小苹果。

à悟空学院:http://t.cn/Rg3fKJD

学院中有Spring Boot相关的课程!点击「阅读原文」进行查看!

SpringBoot视频:http://t.cn/R3QepWG

Spring Cloud视频:http://t.cn/R3QeRZc

SpringBoot Shiro视频:http://t.cn/R3QDMbh

SpringBoot交流平台:http://t.cn/R3QDhU0

SpringData和JPA视频:http://t.cn/R1pSojf

SpringSecurity5.0视频:http://t.cn/EwlLjHh

Sharding-JDBC分库分表实战:http://t.cn/E4lpD6e

以上是关于249.Spring Boot+Spring Security:基于URL动态权限:扩展access()的SpEL表达式的主要内容,如果未能解决你的问题,请参考以下文章

spring boot 之注解

Spring boot??????????????????Spring boot??????MySql,Mybatis???PageHelper??????

Spring Boot 事物回滚

使用 Spring Boot 时如何使用 SpringTemplateEngine

jboss spring boot

spring boot微服务通用部署启动脚本