本文将分别介绍注解和xml的方式来使用spring security ,通过一个简单的demo来演示对url访问进行验证。
因为我用的是gradle来构建项目,先看一下gradle依赖项。
第一步:创建Spring Security Java 配置类。
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("bill").password("abc123").roles("USER");
auth.inMemoryAuthentication().withUser("admin").password("root123").roles("ADMIN");
auth.inMemoryAuthentication().withUser("dba").password("root123").roles("ADMIN","DBA");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/", "/home").permitAll()
.antMatchers("/admin/**").access("hasRole('ADMIN')")
.antMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')")
.and().formLogin()
.and().exceptionHandling().accessDeniedPage("/Access_Denied");
}
}
上面这个类的configureGlobalSecurity方法里的 AuthenticationManagerBuilder配置用户授权和角色信息 。
AuthenticationManagerBuilder (权限管理器创建器)创建负责所有权限请求的AuthenticationManager(权限管理器),使用的是基于内存的权限认证。重写Configure方法,来配置HttpSecurity 来配置基于特定http请求的安全认证。
只有具有ADMIN权限的用户才可以访问符合‘/admin/**’的url。只能够同时具有ADMIN 和 DBA权限的人才可以访问符合‘/db/**’ 的Url 。
formLogin 方法提供了基于表单的权限验证,将会产生一个默认的对用户的表单请求。
使用exceptionHandling().accessDeniedPage() ,在本例中它将获取所有的403(http访问拒绝)异常然后显示我们的用户定义的HTTP403页面。
对应的xml配置:
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">
<http auto-config="true" >
<intercept-url pattern="/" access="permitAll" />
<intercept-url pattern="/home" access="permitAll" />
<intercept-url pattern="/admin**" access="hasRole('ADMIN')" />
<intercept-url pattern="/dba**" access="hasRole('ADMIN') and hasRole('DBA')" />
<form-login authentication-failure-url="/Access_Denied" />
</http>
<authentication-manager >
<authentication-provider>
<user-service>
<user name="bill" password="abc123" authorities="ROLE_USER" />
<user name="admin" password="root123" authorities="ROLE_ADMIN" />
<user name="dba" password="root123" authorities="ROLE_ADMIN,ROLE_DBA" />
</user-service>
</authentication-provider>
</authentication-manager>
</beans:beans>
第二步:创建springSecurityFilte安全过滤器。
public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
}
对应在web.xml的l配置:
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
第三步:创建SpringMVC 配置类。
@Configuration //标识一个类代替xml来配置bean容器
@EnableWebMvc //把WebMvcConfigurationSupport当成
// 配置文件来用,将其中所有标识有@Bean注解的方法配置成bean,这就成了Spring mvc的默认配置
@ComponentScan(basePackages = "security.controller")
@Import({ SecurityConfig.class })
public class AppConfig extends WebMvcConfigurerAdapter {
@Bean //注解的方法都会发布成一个bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
/*@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
//addResourceLocations指的是文件放置的目录,addResoureHandler指的是对外暴露的访问路径
registry.addResourceHandler("/static/**").addResourceLocations("/static/");
}*/
}
第四步:创建springmvc 初始化类public class SpringMvcInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { AppConfig.class };
}
@Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
初始化器继承自AbstractAnnotationConfigDispatcherServletInitializer ,它是所有WebApplicationInitializer 实现的基类。
在Servlet 3.0 环境下,通过实现WebApplicationInitializer 来配置ServletContext 。这意味着我们将不使用web.xml下支持servlet3.0容器发布应用。
第五步:创建Controller控制器
@Controller
public class HelloWorldController {
@RequestMapping(value = { "/", "/home" }, method = RequestMethod.GET)
public String homePage(ModelMap model) {
model.addAttribute("greeting", "Hi, Welcome to mysite. ");
return "welcome";
/*ModelAndView model = new ModelAndView();
model.addObject("greeting", "Spring Security Hello World");
model.setViewName("hello");
return model;*/
}
@RequestMapping(value = "/admin", method = RequestMethod.GET)
public String adminPage(ModelMap model) {
model.addAttribute("user", getPrincipal());
return "admin";
}
@RequestMapping(value = "/db", method = RequestMethod.GET)
public String dbaPage(ModelMap model) {
model.addAttribute("user", getPrincipal());
return "dba";
}
@RequestMapping(value="/logout", method = RequestMethod.GET)
public String logoutPage (HttpServletRequest request, HttpServletResponse response) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null){
new SecurityContextLogoutHandler().logout(request, response, auth);
}
return "welcome";
}
@RequestMapping(value = "/Access_Denied", method = RequestMethod.GET)
public String accessDeniedPage(ModelMap model) {
model.addAttribute("user", getPrincipal());
return "accessDenied";
}
private String getPrincipal(){
String userName = null;
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (principal instanceof UserDetails) {
userName = ((UserDetails)principal).getUsername();
} else {
userName = principal.toString();
}
return userName;
}
}
没有出现 /login,因为Spring Security默认会产生和处理。
注意退出:
首先我们在使用SecurityContextHolder.getContext().getAuthentication() 之前校验该用户是否已经被验证过。
然后调用SecurityContextLogoutHandler().logout(request, response, auth) 来退出。
logout 调用流程:
1 将 HTTP Session 作废,解绑其绑定的所有对象。
2 从SecurityContext移除Authentication 防止并发请求的问题。
3 显式地清楚当前线程的上下文里的值。
在应用的其他地方不再需要处理 退出。
第六步:创建视图。
welcome.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>HelloWorld page</title>
</head>
<body>
Greeting : ${greeting}
This is a welcome page.
</body>
</html>
admin.jsp<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>HelloWorld Admin page</title>
</head>
<body>
Dear <strong>${user}</strong>, Welcome to Admin Page.
<a href="<c:url value="/logout" />">Logout</a>
</body>
</html>
dba.jsp<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>DBA page</title>
</head>
<body>
Dear <strong>${user}</strong>, Welcome to DBA Page.
<a href="<c:url value="/logout" />">Logout</a>
</body>
</html>
accessDenied.jsp<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>AccessDenied page</title>
</head>
<body>
Dear <strong>${user}</strong>, You are not authorized to access this page
<a href="<c:url value="/logout" />">Logout</a>
</body>
</html>
第七步:发布应用到tomcat容器
通过gradle clean,gradle build 构建war包,war文件放到 tomcat的webapps目录下,然后运行 tomcat的bin目录下的startup.sh文件即可。
第八步:验证
打开浏览器访问:http://localhost:8140/springSecurityDemo-1.0-SNAPSHOT/
访问http://localhost:8140/springSecurityDemo-1.0-SNAPSHOT/admin,会被引导到登录页面
输入USER角色账户
提交之后,看到访问拒绝页面,AccessDenied
退出再次访问admin页面
输入错误的密码
输入正确的admin密码,再次登录,显示登录成功
访问http://localhost:8140/springSecurityDemo-1.0-SNAPSHOT/db得到访问拒绝页面
退出回到首页
最后上一张我的项目目录结构图: