spring security 权限(注解)

写在前边整理的知识点都是从其他博客中来,如有侵权,立删!
参考:https://blog.csdn.net/qq_32867467/article/details/103097190

正题:

Spring Security 默认是禁用注解的,要想开启注解,要在继承 WebSecurityConfigurerAdapter 的类加 @EnableMethodSecurity 注解,并在该类中将 AuthenticationManager 定义为 Bean

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true,securedEnabled=true,jsr250Enabled=true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}

我们看到 @EnableGlobalMethodSecurity 分别有 prePostEnabledsecuredEnabledjsr250Enabled 三个字段,其中每个字段代码一种注解支持,默认为 falsetrue 为开启


JSR-250注解

主要注解
@DenyAll  ==  拒绝
@PermitAll  ==  通过
@RolesAllowed
/**
 只要具有USER, ADMIN任意一种权限就可以访问 
这里可以省略前缀ROLE_,实际的权限可能是ROLE_ADMIN
*/
@RolesAllowed({"USER", "ADMIN"}) 

securedEnabled注解

@Secured  ==  在方法上指定安全性要求

可以使用 @Secured 在方法上指定安全性要求 角色/权限等 只有对应 角色/权限 的用户才可以调用这些方法。 如果有人试图调用一个方法,但是不拥有所需的 角色/权限,那会将会拒绝访问将引发异常。
不支持Spring EL表达式

@Secured("ROLE_ADMIN")
@Secured({ "ROLE_DBA", "ROLE_ADMIN" })

prePostEnabled注解

这个开启后支持Spring EL表达式 算是蛮厉害的。如果没有访问方法的权限,会抛AccessDeniedException

@PreAuthorize  ==  适合进入方法之前验证授权

在方法执行之前执行,而且这里可以调用方法的参数,也可以得到参数值,这里利用JAVA8的参数名反射特性,如果没有JAVA8,那么也可以利用Spring Secuirty的@P标注参数,或利用Spring Data的@Param标注参数。

//无java8
@PreAuthorize("#userId == authentication.principal.userId or hasAuthority(‘ADMIN’)")
void changePassword(@P("userId") long userId ){}
//有java8
@PreAuthorize("#userId == authentication.principal.userId or hasAuthority(‘ADMIN’)")
void changePassword(long userId ){}

/**

这里表示在changePassword方法执行之前,判断方法参数userId的值是否等于principal中保存的当前用户的userId,或者当前用户是否具有ROLE_ADMIN权限,两种符合其一,就可以访问该 方法。

*/

@PostAuthorize  ==  检查授权方法之后才被执行

在方法执行之后执行,而且这里可以调用方法的返回值,如果EL为false,那么该方法也已经执行完了,可能会回滚。EL变量returnObject表示返回的对象。

@PostAuthorize("returnObject.userId == authentication.principal.userId or hasPermission(returnObject, 'ADMIN')")
User getUser();


@PostFilter  ==  在方法执行之后执行,而且这里可以调用方法的返回值,然后对返回值进行过滤或处理或修改并返回

在执行方法之后执行,而且这里可以调用方法的返回值,然后对返回值进行过滤或处理。EL变量returnObject表示返回的对象。只有方法返回的集合或数组类型的才可以使用。(与分页技术不兼容)


@PreFilter  ==  在方法执行之前执行,而且这里可以调用方法的参数,然后对参数值进行过滤或处理或修改

EL变量filterObject表示参数,如果有多个参数,可以使用@filterTarget注解参数,只有方法是集合或数组才行(与分页技术不兼容)。


@PreAuthorize 和 @PostAuthorize 中 除了支持原有的权限表达式之外,也是可以支持自定义的。
interface TestPermissionEvaluator {
    boolean check(Authentication authentication);
}

@Service("testPermissionEvaluator")
public class TestPermissionEvaluatorImpl implements TestPermissionEvaluator {

    public boolean check(Authentication authentication) {
        System.out.println("进入了自定义的匹配器" + authentication);
        return false;
    }
}

// 返回true 就是有权限 false 则是无权限 。 然后在方法中这样玩即可

@PreAuthorize("@testPermissionEvaluator.check(authentication)")
public String test0() {
	return "说明你有自定义权限";
}

  • 异常处理
@Component
@Slf4j
public class AccessDeniedAuthenticationHandler implements AccessDeniedHandler {
    private final ObjectMapper objectMapper;

    public AccessDeniedAuthenticationHandler(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }

    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException {
        log.info("没有权限");
        httpServletResponse.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
        httpServletResponse.setContentType("application/json;charset=UTF-8");
        httpServletResponse.getWriter().write(objectMapper.writeValueAsString(e.getMessage()));
    }

}

然后在WebSecurityConfig 中的 configure 中配置即可

http.anyRequest()
    .authenticated()
    .and().exceptionHandling()
    .accessDeniedHandler(accessDeniedAuthenticationHandler);
    

权限表达式

表达式 说明
hasRole([role]) 用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀)
hasAnyRole([role1,role2]) 用户拥有任意一个制定的角色时返回true
hasAuthority([authority]) 等同于hasRole,但不会带有ROLE_前缀
asAnyAuthority([auth1,auth2]) 等同于hasAnyRole
permitAll 永远返回true
denyAll 永远返回false
authentication 当前登录用户的authentication对象
fullAuthenticated 当前用户既不是anonymous也不是rememberMe用户时返回true
hasIpAddress(‘192.168.1.0/24’)) 请求发送的IP匹配时返回true

eg

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin()
                .failureHandler(failureAuthenticationHandler) // 自定义登录失败处理
                .successHandler(successAuthenticationHandler) // 自定义登录成功处理
                .and()
                .logout()
                .logoutUrl("/logout")
                .and()
                .formLogin()
                .loginPage("/login")
                .loginProcessingUrl("/authentication/form") // 自定义登录路径
                .and()
                .authorizeRequests()// 对请求授权
                .antMatchers("/login", "/authentication/require",
                        "/authentication/form").permitAll()// 这些页面不需要身份认证
                .antMatchers("/docker").hasRole("DOCKER")
                .antMatchers("/java").hasRole("JAVA")
                .antMatchers("/java").hasRole("JAVA")
                .antMatchers("/custom")
                .access("@testPermissionEvaluator.check(authentication)")
                .anyRequest()//其他请求需要认证
                .authenticated().and().exceptionHandling()
                .accessDeniedHandler(accessDeniedAuthenticationHandler)
                .and()
                .csrf().disable();// 禁用跨站攻击
    }

自定义权限表达式
access() spring3.0后出了spel 超好用,有了这个我们就可以设置自己的权限验证了

eg access("hasRole('JAVA') or hasRole('DOCKER')")

上述示例代码中的 access("@testPermissionEvaluator.check(authentication)") 的意思就是 去testPermissionEvaluator这个bean里来执行check方法,这里需要注意check 方法必须返回值是boolean

interface TestPermissionEvaluator {
    boolean check(Authentication authentication);
}

@Service("testPermissionEvaluator")
public class TestPermissionEvaluatorImpl implements TestPermissionEvaluator {

    public boolean check(Authentication authentication) {
        //这里可以拿到登陆信息然后随便的去定制自己的权限 随便你怎么查询
        //true就是过,false就是不过
        System.out.println("进入了自定义的匹配器" + authentication);
        return false;
    }
}

示例项目地址: https://github.com/Blackcat308/reimagined-giggle or https://gitee.com/muncle/reimagined-giggle

也可以关注我的博客: https://blog.laocat.cn/

你可能感兴趣的:(java,springcloud,web后端,java,spring,boot,spring,security)