基于 Spring Boot 的 SSM 环境整合十八:整合 spring security 四(自定义未授权访问结果)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xz2001/article/details/86534477

前几篇,增加了对登录失败、成功的结果处理,在上一篇《基于 Spring Boot 的 SSM 环境整合十七:升级 Spring Boot 到 2.0遇到的问题》中解决了FreeMarker模板提示警告的问题。

我将相关的类进行了重命名,主要是为了规范。最后的WebSecurityConfig类如下:

package com.whowii.website4.config;

import java.util.ArrayList;
import java.util.List;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;

import com.whowii.website4.security.ExitSuccessHandler;
import com.whowii.website4.security.LoginFailHander;
import com.whowii.website4.security.LoginProvider;
import com.whowii.website4.security.LoginSuccessHandler;
import com.whowii.website4.security.LoginedDeniedHandler;
import com.whowii.website4.security.NotLoginDeniedHandler;

import freemarker.ext.jsp.TaglibFactory;

/**
 * 登录成功处理
 * 
 * @ClassName: WebSecurityConfig
 * @Description: TODO
 * @author:calvin
 * @date 2019年1月16日 下午8:47:34
 */
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
	@Autowired
	private LoginProvider loginProvider;
	@Autowired
	private LoginSuccessHandler loginSuccessHandler;
	@Autowired
	private LoginFailHander loginFailHander;
	@Autowired
	private FreeMarkerConfigurer templetConfigurer;

	@PostConstruct
	public void freeMarkerConfigurer() {
		List<String> tlds = new ArrayList<String>();
		TaglibFactory taglibFactory = templetConfigurer.getTaglibFactory();
		taglibFactory.setClasspathTlds(tlds);
		if (taglibFactory.getObjectWrapper() == null) {
			taglibFactory.setObjectWrapper(templetConfigurer.getConfiguration().getObjectWrapper());
		}
	}

	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		auth.authenticationProvider(loginProvider);
	}

	@Override
	public void configure(WebSecurity web) throws Exception {
		web.ignoring().antMatchers("/resource/**");
		web.ignoring().antMatchers("/script/**");
		web.ignoring().antMatchers("/ui/**");
		web.ignoring().antMatchers("/favicon.ico");
	}

	protected void configure(HttpSecurity http) throws Exception {
		System.out.println("4>>>>>>>>>>>>>SecurityConfig.configure > http");
		http
			.csrf().disable()
			.headers()
			.frameOptions()	// 解决IFrame拒绝的问题
			.disable()
		.and()
			.authorizeRequests()
			.antMatchers("/manage/demo/hello", "/manage/demo/index").permitAll() // 此页面允许任何人访问,即使未登录
			.antMatchers("/manage/demo/info1").hasAnyRole("ADMIN") // 仅允许 ADMIN 角色的用户访问
			.antMatchers("/manage/demo/info2").hasAnyRole("USER") // 仅允许 USER 角色的用户访问
			.anyRequest().denyAll() // 其他资源禁止访问
		.and()
			.formLogin()
			.loginPage("/manage/demo/login") // 自定义登录页面
			.successHandler(loginSuccessHandler) // 登录成功
			.failureHandler(loginFailHander) // 登录失败
			.permitAll() // 允许任何用户访问
		.and()
			.logout()
			.logoutUrl("/manage/demo/exit") // 退出登录
			.logoutSuccessHandler(new ExitSuccessHandler()) // 退出登录处理
//			.logoutSuccessUrl("/manage/demo/index") // 退出登录成功返回的页面
			.permitAll(); // 允许其他用户访问
		
	}
}

本篇主要解决两个问题:一是未登录用户访问需授权资源时的结果定义,二是已登录用户访问无权限资源时的结果定义。

1、实现 AuthenticationEntryPoint 接口

package com.whowii.website4.security;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;

/**
 * 未登录无权访问处理
 * 
 * @ClassName: LoginEntryPoint
 * @Description: TODO
 * @author:calvin
 * @date 2019年1月16日 下午8:49:04
 */
public class NotLoginDeniedHandler implements AuthenticationEntryPoint {
	@Override
	public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException,
			ServletException {
		response.setHeader("Content-Type", "application/json;charset=utf-8");
		response.getWriter().print("{\"success\":false,\"code\":220,\"message\":\"访问失败:" + exception.getMessage() + "\"}");
		response.getWriter().flush();
	}

}

此类用于处理未登录用户访问需要权限的资源时,如何返回结果。

2、实现 AccessDeniedHandler 接口

package com.whowii.website4.security;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;

/**
 * 登录无权访问处理
 * 
 * @ClassName: LoginDeniedHandler
 * @Description: TODO
 * @author:calvin
 * @date 2019年1月16日 下午8:48:48
 */
public class LoginedDeniedHandler implements AccessDeniedHandler {
	@Override
	public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException exception) throws IOException,
			ServletException {
		response.setHeader("Content-Type", "application/json;charset=utf-8");
		response.getWriter().print("{\"success\":false,\"code\":210,\"message\":\"访问失败:" + exception.getMessage() + "\"}");
		response.getWriter().flush();
	}
}

此类用于处理已登录用户访问无权限的资源时,如何返回结果。

3、注册处理对象

修改WebSecurityConfig类,注册两个处理对象,完成后的代码如下:

package com.whowii.website4.config;

import java.util.ArrayList;
import java.util.List;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;

import com.whowii.website4.security.ExitSuccessHandler;
import com.whowii.website4.security.LoginFailHander;
import com.whowii.website4.security.LoginProvider;
import com.whowii.website4.security.LoginSuccessHandler;
import com.whowii.website4.security.LoginedDeniedHandler;
import com.whowii.website4.security.NotLoginDeniedHandler;

import freemarker.ext.jsp.TaglibFactory;

/**
 * 登录成功处理
 * 
 * @ClassName: WebSecurityConfig
 * @Description: TODO
 * @author:calvin
 * @date 2019年1月16日 下午8:47:34
 */
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
	@Autowired
	private LoginProvider loginProvider;
	@Autowired
	private LoginSuccessHandler loginSuccessHandler;
	@Autowired
	private LoginFailHander loginFailHander;
	@Autowired
	private FreeMarkerConfigurer templetConfigurer;

	@PostConstruct
	public void freeMarkerConfigurer() {
		List<String> tlds = new ArrayList<String>();
		TaglibFactory taglibFactory = templetConfigurer.getTaglibFactory();
		taglibFactory.setClasspathTlds(tlds);
		if (taglibFactory.getObjectWrapper() == null) {
			taglibFactory.setObjectWrapper(templetConfigurer.getConfiguration().getObjectWrapper());
		}
	}

	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		auth.authenticationProvider(loginProvider);
	}

	@Override
	public void configure(WebSecurity web) throws Exception {
		web.ignoring().antMatchers("/resource/**");
		web.ignoring().antMatchers("/script/**");
		web.ignoring().antMatchers("/ui/**");
		web.ignoring().antMatchers("/favicon.ico");
	}

	protected void configure(HttpSecurity http) throws Exception {
		System.out.println("4>>>>>>>>>>>>>SecurityConfig.configure > http");
		http
			.csrf().disable()
			.headers()
			.frameOptions()	// 解决IFrame拒绝的问题
			.disable()
		.and()
			.authorizeRequests()
			.antMatchers("/manage/demo/hello", "/manage/demo/index").permitAll() // 此页面允许任何人访问,即使未登录
			.antMatchers("/manage/demo/info1").hasAnyRole("ADMIN") // 仅允许 ADMIN 角色的用户访问
			.antMatchers("/manage/demo/info2").hasAnyRole("USER") // 仅允许 USER 角色的用户访问
			.anyRequest().denyAll() // 其他资源禁止访问
		.and()
			.formLogin()
			.loginPage("/manage/demo/login") // 自定义登录页面
			.successHandler(loginSuccessHandler) // 登录成功
			.failureHandler(loginFailHander) // 登录失败
			.permitAll() // 允许任何用户访问
		.and()
			.logout()
			.logoutUrl("/manage/demo/exit") // 退出登录
			.logoutSuccessHandler(new ExitSuccessHandler()) // 退出登录处理
//			.logoutSuccessUrl("/manage/demo/index") // 退出登录成功返回的页面
			.permitAll() // 允许其他用户访问
		.and()
			.exceptionHandling()
			.accessDeniedHandler(new LoginedDeniedHandler()) // 当登录后访问无权资源时(默认跳转到报错页面)
			.authenticationEntryPoint(new NotLoginDeniedHandler()); // 当未登录访问资源时(默认是跳转到登录页面)
		
	}
}

4、测试结果

启动应用,当未登录时访问 http://127.0.0.1:8080/manage/demo/info1 结果如下:

使用 admin 登录后,访问 http://127.0.0.1:8080/manage/demo/info2 (需 USER 角色)结果如下:

猜你喜欢

转载自blog.csdn.net/xz2001/article/details/86534477
今日推荐