Spring Security Study Notes (12) Exceptions and Permission Management Use

reference video

abnormal

Anomalies in SS are mainly divided into two types

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

insert image description here
insert image description here
We insert data in the database
insert image description here
insert image description here
At this point we log in to the user with id 1 and
insert image description here
insert image description here
customize exception handling

.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();
                    }
                })

It will appear if we log in to other unprivileged users for access.
insert image description here

Source code analysis: This involves FilterSecurityInterceptora method in a class

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();
	}

insert image description here
insert image description here
reference article

authority management

SpringSecurityTwo rights management strategies are provided.

FilterSecurityInterceptor: Filter-based permission management, intercepting the request and verifying the permission according to the address of the http request. This way the request is processed before it reaches the method.
MethodSecurityInterceptor: Based on method-level interception processing, it uses the idea of ​​aop, which means that the request arrival method is executed before the method call.

Method-Based Rights Management

For the following annotations to take effect, they must be added to the configuration class to @EnableGlobalMethodSecurity(jsr250Enabled = true,prePostEnabled = true,proxyTargetClass = true,securedEnabled = true)enable these annotations.

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

insert image description here

insert image description here

@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测试");
    }

Guess you like

Origin blog.csdn.net/qq_45401910/article/details/127227667