• Spring Security 实战(使用Spring Boot项目演示)


    Spring Security 的应用越来越广泛,它支持页面级别、API级别 以及方法级别的权限控制,可以说项目中的绝大部分场景都能适用。不管哪种级别的权限控制,都需要进行以下的步骤 (使用Spring Boot项目演示):

    1. 加入Spring Boot Security的依赖 (不需要版本号,因为Spring boot的parent pom里面就已经有版本号了):
    compile "org.springframework.boot:spring-boot-starter-security"

     

    2. 启动类加注解

    注意这里有个地雷,我不小心踩到过,如果你的Spring Boot版本比较低的话,切记要加上@ComponentScan注解,不然你会遇到绵绵不断的缺少各种依赖,能烦死。

    @EnableGlobalMethodSecurity(prePostEnabled = true) 这个注解只是在你需要使用方法级别的权限认证的时候需要加的,否则可以不加。

     

    3. 新加一个继承了WebSecurityConfigurerAdapter的配置类,这可以说是Spring Security的核心了,我们可以在这个类里面配置用户权限,过滤器,认证管理器,拦截路径等。

    需要加上@Configuration注解和@EnableWebSecurity注解

     

    3.1. 在SecurityConfig中配置用户角色权限:

    可以直接在启动的时候直接hard-coding方式将用户角色初始化到内存中;

    也可以通过DataSource从数据库抓取用户角色信息;

    另外还可以通过解析request里面的username & password动态的给用户分配角色权限。

     

    3.2. 在SecurityConfig中配置路径拦截

    配置路径和访问权限可以参考Spring Security的官方文档,大致简单介绍一下:

    这个配置方式有点类似构建模式,一步步去构建HttpSecurity对象。

    authorizeRequests()这个表示获取URL注册对象,得到这个对象之后可以进行一些URL匹配操作

    antMatchers() 这个表示使用Ant格式来匹配路径,也就意味着你可以使用Ant里面的通配符

    hasRole() 很明显,有参数里面指定的角色才可以访问这个路径

    access() 参数里面是一个Spring EL表达式,只有当表达式返回true才允许访问

    anyRequest() 表示所有请求,类似AntMathchers(“/**”) 注意这个放到后面,如果放到前面,会覆盖掉前面指定的哪些具体路径

    permitAll() 无条件让所有请求通过

    denyAll() 无条件让所有请求不通过

    @Override
    
    public void configure(HttpSecurity http) throws Exception {
    
        http.csrf().disable().authorizeRequests()
    
                .antMatchers("/upteam/test/useraccess").hasRole("USER")
    
                .antMatchers("/upteam/test/aeminaccess").access("hasRole('ADMIN')")
    
                .anyRequest().permitAll();
    
        //.and().exceptionHandling().accessDeniedHandler(myHandleAccessDeniedException);
    
    }

    上面这个配置的意思是首先禁用csrf,然后如果访问useraccess API需要有USER权限,如果访问 adminaccess API需要有ADMIN权限,其他的一律让它们通过,不做判断。

     

    4. 对应的页面,API或方法:

    @RequestMapping(value = "/useraccess", method = RequestMethod.POST)
    
    public String testUserAccess() {
    
        System.out.println("Comming in user access");
    
        return " ---- user access";
    
    }
    
    
    
    @RequestMapping(value = "/adminaccess", method = RequestMethod.POST)
    
    public String testAdminAccess() {
    
        System.out.println("Comming in admin access");
    
        return " ---- admin access";
    
    }

     

     

    上面演示的这种适用于页面或API,因为是在配置里面通过路径去指定的,下面还要介绍一个方法级别的控制。

    如果要加入方法级别的权限认证(当然,方法级别的也同样可以控制用户访问API,毕竟在Spring框架中 API是定义在方法上面的),那么:

    1. 首先需要在启动类中加入@EnableGlobalMethodSecurity(prePostEnabled = true)这个注解。

    2. 同样可以像上面介绍的那样在SecurityConfig里面去配置用户及用户的角色,当然更灵活的我们可以自己去定义适用于每个request的用户角色:

    这是用户角色Bean,我自己定义它有一个hasRole方法,你也可以定义别的方法,只要到时候在方法上面的条件表达式能判断即可

    public class UserAccess {
    
    
    
        public boolean hasRole(String role) {
    
            if ("Read".equalsIgnoreCase(role)) {
    
                return true;
    
            }
    
            return false;
    
        }
    
    }

     

    在上面那个SecurityConfig里面配置下这个用户角色的Bean,注意我这里将Bean的作用域定义成Request,也就是每个request过来都会创建一个新的Bean,而不是默认的单例Bean。这样我就可以根绝每个request带过来的信息初始化这个Bean 并为之授予相应的权限了。这里为了演示简单,我直接初始化的。

    @Bean("userAccess")
    
    @Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
    
    public UserAccess userAccessBean() {
    
        return new UserAccess();
    
    }

     

    另外,也可以加一个AccessDeniedHandler配置,自己定义当方法禁止访问时返回的消息:

    @Component
    
    public class MyHandleAccessDeniedException implements AccessDeniedHandler {
    
        @Override
    
        public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
    
            httpServletResponse.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
    
            httpServletResponse.setStatus(HttpServletResponse.SC_FORBIDDEN);
    
            httpServletResponse.getWriter().write("{"error": "access_denied", "error_description": "" + e.getMessage() + ""}");
    
        }
    
    }

     

    在SecurityConfig中配置一下这个AccessDeniedHandler才会起作用:

    @Autowired
    
    private AccessDeniedHandler myHandleAccessDeniedException;
    
     
    @Override
    
    public void configure(HttpSecurity http) throws Exception {
    
        http.csrf().disable().authorizeRequests()
    
                .antMatchers("/upteam/test/useraccess").hasRole("USER")
    
                .antMatchers("/upteam/test/aeminaccess").access("hasRole('ADMIN')")
    
                .anyRequest().permitAll()
    
        .and().exceptionHandling().accessDeniedHandler(myHandleAccessDeniedException);
    
    }

     

    3. 好了,接下来可以在方法上加入@PreAuthorize注解,里面定义一个表达式,只要结果返回true就可以访问这个方法,否则会走刚才定义的AccessDeniedHandle返回错误消息。

    要先注入这个UserAccess Bean哦。

    @Autowired
    
    private UserAccess userAccess;
    
    
    
    @PreAuthorize("@userAccess.hasRole('Read')")
    
    @RequestMapping(value = "/readaccess", method = RequestMethod.POST)
    
    public String testRead() {
    
        userAccess.hasRole("Read");
    
        System.out.println("Comming in read access");
    
        return " ---- read access";
    
    }
    
    
    
    @PreAuthorize("@userAccess.hasRole('Write')")
    
    @RequestMapping(value = "/writeaccess", method = RequestMethod.POST)
    
    public String testWrite() {
    
        System.out.println("Comming in write access");
    
        return " ---- write access";
    
    }

     

  • 相关阅读:
    POJ 2923 Relocation ★(状态压缩+01背包)
    POJ 1062 昂贵的聘礼 (带限制的最短路)
    HDU 4355 Party All the Time (三分求凸函数极值)
    POJ 1860 Currency Exchange (BellmanFord)
    POJ 2923 Relocation ★(状态压缩+01背包)
    【HNOI2011】数学作业(BZOJ 2326)
    POJ 1062 昂贵的聘礼 (带限制的最短路)
    作为当代大学生,面对着信息增长加快,老化周期变短,你应该如何做?
    作为当代大学生,面对着信息增长加快,老化周期变短,你应该如何做?
    信息分析与预测考前模拟试题
  • 原文地址:https://www.cnblogs.com/cnsec/p/13407141.html
Copyright © 2020-2023  润新知