SpringSecurity+JWT项目实战之Java权限管理实战(五)--访问控制

前言

本文是参考尚学堂SpringSecurity精讲,仅作为学习记录使用。

这个系列设计到的技术点如下:

  • SpringSecurity
  • Oauth2
  • SpringSecurity + Oauth2
  • SpringSecurity +JWT
  • SpringSecurity + Oauth2
  • SpringSecurity + Oauth2 + JWT
背景

之前学习的登录用户权限判断实际上底层实现都是调用access(表达式)。现在我们来看一下这个权限控制底层的逻辑。

  • access()方法使用
    可以通过 access() 实现和之前学习的权限控制完成相同的功能。以 hasRole 和 和 permitAll 举例
    在这里插入图片描述
    在这里插入图片描述
  • 使用自定义方法
    虽然这里面已经包含了很多的表达式(方法)但是在实际项目中很有可能出现需要自己自定义逻辑的情况。判断登录用户是否具有访问当前 URL 权限。
  • 新建接口及实现类
  • MyService
package com.mjdai.springsecurity;

import org.springframework.security.core.Authentication;

import javax.servlet.http.HttpServletRequest;

public interface MyService {
    boolean hasPermission(HttpServletRequest request, Authentication authentication);
}

  • MyServiceImpl
package com.mjdai.springsecurity.service;

import com.mjdai.springsecurity.MyService;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import javax.servlet.http.HttpServletRequest;
import java.util.Collection;

public class MyServiceImpl implements MyService {
    @Override
    public boolean hasPermission(HttpServletRequest request, Authentication
            authentication) {
        Object obj = authentication.getPrincipal();
        if (obj instanceof UserDetails) {
            UserDetails userDetails = (UserDetails) obj;
            Collection<? extends GrantedAuthority> authorities =
                    userDetails.getAuthorities();
            return authorities.contains(new
                    SimpleGrantedAuthority(request.getRequestURI()));
        }
        return false;
    }
}

  • 修改配置类
http.authorizeRequests()
                // login.html不需要被认证
//                .antMatchers("/login.html").permitAll()
                .antMatchers("/login.html").access("permitAll")
                // error.html不需要被认证
                .antMatchers("/error.html").permitAll()
                // 所有请求都必须被认证,必须登录后被访问
//                .antMatchers("/main.html").hasAuthority("admin")
//                .antMatchers("/main.html").hasRole("abd")
                .antMatchers("/main.html").access("hasRole(\"abd\")")
                .anyRequest().access("@myServiceImpl.hasPermission(request,authentication)")
                .anyRequest().authenticated();
基于注解的访问控制

在 Spring Security 中提供了一些访问控制的注解。这些注解都是默认是都不可用的,需要通过@EnableGlobalMethodSecurity 进行开启后使用。如果设置的条件允许,程序正常执行。如果不允许会报 500,不允许访问。
org.springframework.security.access.AccessDeniedException
这些注解可以写到 Service 接口或方法上,也可以写到 Controller或 Controller 的方法上。通常情况下都是写在控制器方法上的,控制接口URL是否允许被访问。

  • @Secured
    @Secured 是专门用于判断是否具有角色的。能写在方法或类上。参数要以 ROLE_开头。
package org.springframework.security.access.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Secured {
	/**
	 * Returns the list of security configuration attributes (e.g.&nbsp;ROLE_USER, ROLE_ADMIN).
	 *
	 * @return String[] The secure method attributes
	 */
	String[] value();
}
  • 开启注解
    在 启 动 类 ( 也 可 以 在 配 置 类 等 能 够 扫 描 的 类 上 ) 上 添 加
    @EnableGlobalMethodSecurity(securedEnabled = true)
@SpringBootApplication
@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)
public class MjdaiSpringSecurityApplication {
    public static void main(String[] args) {
        SpringApplication.run(MjdaiSpringSecurityApplication.class, args);
    }
}

在控制器方法上添加@Secured 注解

@Secured("ROLE_abc")
 @RequestMapping(value = "/toMain",method = RequestMethod.POST)
 public String toMain(){
        System.out.println("到这里了吗?");
        return "redirect:main.html";
 }
  • @PreAuthorize/@PostAuthorize
    @PreAuthorize 和@PostAuthorize 都是方法或类级别注解。
  1. @PreAuthorize 表示访问方法或类在执行之前先判断权限,大多情况下都是使用这个注解,注解的参数和access()方法参数取值相同,都是权限表达式。
  2. @PostAuthorize 表示方法或类执行结束后判断权限,此注解很少被使用到。
  • 开启注解
    @EnableGlobalMethodSecurity(prePostEnabled = true)
  • 添加@PreAuthorize
    在控制器方法上添加@PreAuthorize,参数可以是任何 access()支持的表达式
@PreAuthorize("hasRole('ROLE_abc')")
@RequestMapping("/toMain")

版权声明:本文为daimeijin原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。