SpringSecurity学习笔记(十二)异常以及权限管理使用

参考视频

异常

SS中的异常主要分为两种

AuthenticationException authenticationException;//认证异常
AccessDeniedException accessDeniedException;//授权异常

在这里插入图片描述
在这里插入图片描述
我们在数据库中插入数据
在这里插入图片描述
在这里插入图片描述
此时我们登录id为1的用户,
在这里插入图片描述
在这里插入图片描述
自定义异常处理

.and()
                .exceptionHandling()
                .accessDeniedHandler(new AccessDeniedHandler() {
    
    
                    @Override
                    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
    
    
                        response.setStatus(HttpStatus.FORBIDDEN.value());
                        response.setContentType("application/json;charset=utf-8");
                        response.getWriter().write("无权限访问。");
                        response.flushBuffer();
                    }
                })
                .authenticationEntryPoint(new AuthenticationEntryPoint() {
    
    
                    @Override
                    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
    
    
                        response.setStatus(HttpStatus.UNAUTHORIZED.value());
                        response.setContentType("application/json;charset=utf-8");
                        response.getWriter().write("尚未认证,请进行认证操作!");
                        response.flushBuffer();
                    }
                })

如果我们登录了其他的无权限的用户进行访问则出现。
在这里插入图片描述

源码分析:这里面涉及到一个类FilterSecurityInterceptor里面的方法

public void invoke(FilterInvocation fi) throws IOException, ServletException {
    
    
		if ((fi.getRequest() != null)
				&& (fi.getRequest().getAttribute(FILTER_APPLIED) != null)
				&& observeOncePerRequest) {
    
    
			// filter already applied to this request and user wants us to observe
			// once-per-request handling, so don't re-do security checking
			fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
		}
		else {
    
    
			// first time this request being called, so perform security checking
			if (fi.getRequest() != null && observeOncePerRequest) {
    
    
				fi.getRequest().setAttribute(FILTER_APPLIED, Boolean.TRUE);
			}
//这里面会进行判断当前这个请求需要什么权限,用户有没有权限
			InterceptorStatusToken token = super.beforeInvocation(fi);

			try {
    
    
				fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
			}
			finally {
    
    
				super.finallyInvocation(token);
			}

			super.afterInvocation(token, null);
		}
	}
protected InterceptorStatusToken beforeInvocation(Object object) {
    
    
		Assert.notNull(object, "Object was null");
		final boolean debug = logger.isDebugEnabled();

		if (!getSecureObjectClass().isAssignableFrom(object.getClass())) {
    
    
			throw new IllegalArgumentException(
					"Security invocation attempted for object "
							+ object.getClass().getName()
							+ " but AbstractSecurityInterceptor only configured to support secure objects of type: "
							+ getSecureObjectClass());
		}
		//下面这个方法判断当前这个请求路径是否需要什么权限
		Collection<ConfigAttribute> attributes = this.obtainSecurityMetadataSource()
				.getAttributes(object);

		if (attributes == null || attributes.isEmpty()) {
    
    
			if (rejectPublicInvocations) {
    
    
				throw new IllegalArgumentException(
						"Secure object invocation "
								+ object
								+ " was denied as public invocations are not allowed via this interceptor. "
								+ "This indicates a configuration error because the "
								+ "rejectPublicInvocations property is set to 'true'");
			}

			if (debug) {
    
    
				logger.debug("Public object - authentication not attempted");
			}

			publishEvent(new PublicInvocationEvent(object));

			return null; // no further work post-invocation
		}

		if (debug) {
    
    
			logger.debug("Secure object: " + object + "; Attributes: " + attributes);
		}

		if (SecurityContextHolder.getContext().getAuthentication() == null) {
    
    
			credentialsNotFound(messages.getMessage(
					"AbstractSecurityInterceptor.authenticationNotFound",
					"An Authentication object was not found in the SecurityContext"),
					object, attributes);
		}

		Authentication authenticated = authenticateIfRequired();

		// Attempt authorization
		try {
    
    
			//这里对当前的用户进行权限的判断
			this.accessDecisionManager.decide(authenticated, object, attributes);
		}
		catch (AccessDeniedException accessDeniedException) {
    
    
			publishEvent(new AuthorizationFailureEvent(object, attributes, authenticated,
					accessDeniedException));

			throw accessDeniedException;
		}

		if (debug) {
    
    
			logger.debug("Authorization successful");
		}

		if (publishAuthorizationSuccess) {
    
    
			publishEvent(new AuthorizedEvent(object, attributes, authenticated));
		}

		// Attempt to run as a different user
		Authentication runAs = this.runAsManager.buildRunAs(authenticated, object,
				attributes);

		if (runAs == null) {
    
    
			if (debug) {
    
    
				logger.debug("RunAsManager did not change Authentication object");
			}

			// no further work post-invocation
			return new InterceptorStatusToken(SecurityContextHolder.getContext(), false,
					attributes, object);
		}
		else {
    
    
			if (debug) {
    
    
				logger.debug("Switching to RunAs Authentication: " + runAs);
			}

			SecurityContext origCtx = SecurityContextHolder.getContext();
			SecurityContextHolder.setContext(SecurityContextHolder.createEmptyContext());
			SecurityContextHolder.getContext().setAuthentication(runAs);

			// need to revert to token.Authenticated post-invocation
			return new InterceptorStatusToken(origCtx, true, attributes, object);
		}
	}
public void decide(Authentication authentication, Object object,
			Collection<ConfigAttribute> configAttributes) throws AccessDeniedException {
    
    
		int deny = 0;

		for (AccessDecisionVoter voter : getDecisionVoters()) {
    
    
			int result = voter.vote(authentication, object, configAttributes);

			if (logger.isDebugEnabled()) {
    
    
				logger.debug("Voter: " + voter + ", returned: " + result);
			}

			switch (result) {
    
    
			case AccessDecisionVoter.ACCESS_GRANTED:
				return;

			case AccessDecisionVoter.ACCESS_DENIED:
				deny++;

				break;

			default:
				break;
			}
		}

		if (deny > 0) {
    
    
			throw new AccessDeniedException(messages.getMessage(
					"AbstractAccessDecisionManager.accessDenied", "Access is denied"));
		}

		// To get this far, every AccessDecisionVoter abstained
		checkAllowIfAllAbstainDecisions();
	}

在这里插入图片描述
在这里插入图片描述
参考文章

权限管理

SpringSecurity提供了两种权限管理的策略。

FilterSecurityInterceptor:基于过滤器的权限管理,将请求拦截下来根据http请求的地址进行权限的校验你。这种方式是请求到达方法之前进行处理的。
MethodSecurityInterceptor:基于方法级别的拦截处理,利用的是aop的思想,这种是请求到达方法在方法调用前执行。

基于方法的权限管理

下面这几个注解想要生效,必须在配置类上面加上@EnableGlobalMethodSecurity(jsr250Enabled = true,prePostEnabled = true,proxyTargetClass = true,securedEnabled = true)表示启用这些注解。

@PreAuthorize("hasRole('admin')")
@PostAuthorize("")
@PreFilter("")

在这里插入图片描述

在这里插入图片描述

@GetMapping("/admin/test")
    @PreAuthorize("hasRole('admin') and authentication.name=='dongmu'")
    //#name取得是接口上面的参数
    @PostAuthorize("authentication.name == #name")
    @PreFilter("hasAuthority('admin')")
    @ResponseBody
    public String admin(String name){
    
    
        return "这是一个admin用户才能访问的界面。";
    }
    @GetMapping("/public/filter")
    //下面这个表达式表示只是保留值是奇数的结果
    @PreFilter(value = "filterObject%2!=0",filterTarget = "list")
    public void filter(@RequestParam("ids") List<Integer> list){
    
    
        for (Integer integer : list) {
    
    
            System.out.println(integer);
        }
    }

    //下面这个是或的关系,只要拥有一个权限就可以访问这个接口
    @Secured({
    
    "ROLE_admin","ROLE_user"})
    @GetMapping("/public/secure")
    public void secure(){
    
    
        System.out.println("secure测试");
    }

猜你喜欢

转载自blog.csdn.net/qq_45401910/article/details/127227667