
這篇文章主要記錄如何在Spring MVC專案中使用Spring Security模組來做Access的保護
一樣會透過一個簡單範例來介紹:
首先,一樣先放上最後建立好的專案結構,如下所示 :

1. 先在NetBeans中建立Maven的Web專案,並在pom.xml中加入所需的dependency
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${springframework.version}</version>
</dependency>
<!-- Spring Security -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${springsecurity.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${springsecurity.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
2. 建立Spring Security要用到的Configuration Class (SecurityConfiguration.java)
package allen0818.practice.springsecurityprac.configuration;
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.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
/**
*
* @author allen0818
*/
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("allen0818").password("123456").roles("USER");
auth.inMemoryAuthentication().withUser("admin").password("root123").roles("ADMIN");
auth.inMemoryAuthentication().withUser("dba").password("root123").roles("ADMIN","DBA");//dba have two roles.
}
@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");
}
}
在這邊程式做了幾件事:
(1) 在configureGlobalSecurity這個方法中為特定的使用者綁定相對應的Role
(2) 這邊採的是inMemory的認證機制,另外還有提供JDBC, LDAP ...等其他認證機制
(3) 在configure這個方法中我們設定了哪些路徑下只允許擁有哪些Role的使用者進入,permitAll()表示不用驗證可直接進入
(4) .formLogin()方法可讓Spring Security自動產生一個簡易的使用者認證頁面
(5) .exceptionHandling().accessDeniedPage用來導向所有產生403錯誤的頁面(即Access Denied的錯誤)
3. 建立一個Initial Class (SecurityWebApplicationInitializer.java),以註冊剛剛所建立的Configuration
package allen0818.practice.springsecurityprac.configuration;
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
/**
*
* @author allen0818
*/
public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
}
4. 加入Controller (HelloWorldController.java)
package allen0818.practice.springsecurityprac.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
*
* @author allen0818
*/
@Controller
public class HelloWorldController {
@RequestMapping(value = { "/", "/home" }, method = RequestMethod.GET)
public String homePage(ModelMap model) {
model.addAttribute("greeting", "Hi, Welcome to mysite. ");
return "welcome";
}
@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;
}
}
從程式碼中可以看到Spring Security如何封裝使用者的驗證資訊,並提供了Logout的方法
5. 建立Spring MVC的Configuration Class (SpringMvcConfiguration.java)
package allen0818.practice.springsecurityprac.configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;
/**
*
* @author allen0818
*/
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "allen0818.practice.springsecurityprac")
public class SpringMvcConfiguration {
@Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
}
6. 建立Spring MVC的Initializer Class(SpringMvcInitializer.java)
package allen0818.practice.springsecurityprac.configuration;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
/**
*
* @author allen0818
*/
public class SpringMvcInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { SpringMvcConfiguration.class };
}
@Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
7. 加入前端顯示所需要的views
welcome.jsp
<%--
Document : welcome
Created on : 2016/5/11, 下午 04:06:15
Author : allen0818
--%>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Welcome Page</title>
</head>
<body>
Greeting : ${greeting}
This is a welcome page.
</body>
</html>
admin.jsp
<%--
Document : admin
Created on : 2016/5/11, 下午 04:06:02
Author : allen0818
--%>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>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
<%--
Document : dba
Created on : 2016/5/11, 下午 04:06:08
Author : allen0818
--%>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<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
<%--
Document : accessDenied
Created on : 2016/5/11, 下午 04:05:53
Author : allen0818
--%>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<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>
呈現畫面如下(請觀察上方網址列):
1. welcome page

2. Spring Security提供的登入頁面

3. 登入失敗畫面

4. 進入未授權頁面畫面

5. Logout後導回至Welcome Page

還蠻多東西的,初次接觸的朋友可能需要好好消化一下~
這篇文章的內容主要是參考這篇教學整理而成,若需要有關Spring Security更詳細的介紹
可以參考官方釋出的document
參考資料:
1. http://websystique.com/spring-security/spring-security-4-hello-world-annotation-xml-example/
2. http://docs.spring.io/spring-security/site/docs/4.0.1.RELEASE/reference/htmlsingle/
留言列表

