Spring Security例子

Spring security 简单例子

使用xml方式

pom.xml引入依赖

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.spsecurity.xml</groupId>
	<artifactId>spsecurity-xml</artifactId>
	<packaging>war</packaging>
	<version>0.0.1-SNAPSHOT</version>
	<name>spsecurity-xml Maven Webapp</name>
	<url>http://maven.apache.org</url>

	<properties>
		<spring.version>3.2.8.RELEASE</spring.version>
		<spring.security.version>3.2.3.RELEASE</spring.security.version>
	</properties>
	<dependencies>

		<!-- spring -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-web</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<!-- spring security -->
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-web</artifactId>
			<version>${spring.security.version}</version>
		</dependency>

		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-config</artifactId>
			<version>${spring.security.version}</version>
		</dependency>

		<!-- servlet -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>javax.servlet-api</artifactId>
			<version>3.1.0</version>
			<scope>provided</scope>
		</dependency>

		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>1.2</version>
		</dependency>

	</dependencies>

	<build>
		<finalName>spsecurity-xml</finalName>

		<plugins>

			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-war-plugin</artifactId>
				<version>3.3.1</version>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.6.2</version>
				<configuration>
					<source>1.7</source>
					<target>1.7</target>
					<encoding>UTF-8</encoding>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

web.xml 配置

<web-app id="webId" version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

  <display-name>Archetype Created Web Application</display-name>
  
  	<!-- 加载spring容器 -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:spring/spring-security.xml</param-value>
	</context-param>
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

	<filter>
		<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前端控制器 -->
	<servlet>
		<servlet-name>springmvc</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:spring/spring-mvc.xml</param-value>
		</init-param>
	</servlet>
	<servlet-mapping>
		<servlet-name>springmvc</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>

	<!-- post乱码过虑器 -->
	<filter>
		<filter-name>CharacterEncodingFilter</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
		<init-param>
			<param-name>encoding</param-name>
			<param-value>utf-8</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>CharacterEncodingFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	
</web-app>

spring配置

spring-mvc.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context 
		http://www.springframework.org/schema/context/spring-context.xsd">

	<!-- 扫描controller的包 -->
	<context:component-scan base-package="com.spsecurity.xml.controller" />
	<!-- 配置JSP视图解析器 -->
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/views/" />
		<property name="suffix" value=".jsp" />
		<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
	</bean>

</beans>

spring-security.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:security="http://www.springframework.org/schema/security"
	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">

	<security:http auto-config="true" use-expressions="true">

		<security:intercept-url pattern="/login" access="permitAll()" />
		<security:intercept-url pattern="/**" access="hasRole('ROLE_USER')" />

		<!-- <security:http auto-config="true" use-expressions="false"> 
		    <security:intercept-url pattern="/login" access="IS_AUTHENTICATED_ANONYMOUSLY" />
		    <security:intercept-url pattern="/**" access="ROLE_USER" /> -->

		<security:form-login login-page="/login" 
			default-target-url="/index"
			authentication-failure-url="/login?error" 
			username-parameter="username" password-parameter="password" />
			
		<security:logout logout-success-url="/login?logout" />
	</security:http>
	
	<security:authentication-manager>
		<security:authentication-provider >
			<security:user-service>
				<security:user name="user" password="user" authorities="ROLE_USER" />
				<security:user name="admin" password="admin" authorities="ROLE_USER, ROLE_ADMIN" />
			</security:user-service>
		</security:authentication-provider>
	</security:authentication-manager>

</beans>

自定义jsp页面

登录login.sjp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>登录</title>

</head>
<body>

	<span id="msg"></span>

	<form action="<%=request.getContextPath()%>/j_spring_security_check" method="post">
		登录名:<input name="username" /> <br /> 
		密码:<input name="password" type="password" /><br> 
		<input type="submit" value="登录" />
	</form>

	<script type="text/javascript">
		var msg = "<%=request.getAttribute("msg")%>";
		document.getElementById("msg").innerHTML = msg;
	</script>
	
</body>
</html>

首页
index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
	首页
	<br /> ....
	<br />
	<a href="<%=request.getContextPath()%>/j_spring_security_logout">退出登录</a>

</body>
</html>

Java代码

IndexController.java

package com.spsecurity.xml.controller;

import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/")
public class IndexController {

    @RequestMapping("/login")
    public String login(Model model, HttpServletRequest request) {
        String msg = "";
        String error = request.getParameter("error");
        String logout = request.getParameter("logout");
        if (error != null) {
            msg = "用户名或者密码错误";
        } else if (logout != null) {
            msg = "退出登录成功";
        }
        model.addAttribute("msg", msg);
        return "login";
    }

    @RequestMapping("/index")
    public String index(String type) {
        return "index";
    }
}

使用注解方式

pom.xml引入依赖

与上面雷同,多一个tomcat插件配置

<plugin>
	<groupId>org.apache.tomcat.maven</groupId>
	<artifactId>tomcat7-maven-plugin</artifactId>
	<version>2.2</version>
</plugin>

jsp页面

与上面相同,略

Java代码

IndexContoller.java 雷同,略

AppConfig.java

/**
 * 对应 ContextLoaderListener的配置
 */
@Configuration
@ComponentScan(basePackages = "com.spsecurity.annotation", excludeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION, value = Controller.class) })
public class AppConfig {
    // 在此配置除了Controller的其它bean,比如:数据库链接池、事务管理、业务等。
}

MvcConfig.java

/**
 * 对应DispatcherServlet配置
 */
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.spsecurity.annotation.controller", includeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION, value = Controller.class) })
public class MvcConfig extends WebMvcConfigurerAdapter {

    // 视图解析器
    @Bean
    public InternalResourceViewResolver viewResolver() {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setPrefix("/WEB-INF/views/");
        viewResolver.setSuffix(".jsp");
        viewResolver.setViewClass(JstlView.class);
        return viewResolver;
    }
}

SecurityConfig.java

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("admin").password("admin").roles("ADMIN").and().withUser("user")
                .password("user").roles("USER");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/login").permitAll().antMatchers("/**").hasRole("ADMIN").and().formLogin()
                .loginPage("/login").loginProcessingUrl("/j_spring_security_check").defaultSuccessUrl("/index")
                .failureUrl("/login?error").usernameParameter("username").passwordParameter("password").and().logout()
                .logoutUrl("/j_spring_security_logout").logoutSuccessUrl("/login?logout").and().csrf().disable();
    }

    /**
     * 系统自带登录页面
     */
//    @Override
//    protected void configure(HttpSecurity http) throws Exception {
//        http.authorizeRequests().antMatchers("/**").hasRole("ADMIN").and().formLogin().defaultSuccessUrl("/index").and()
//                .logout().logoutUrl("/j_spring_security_logout").and().csrf();
//    }

}

SpringSecurityInitializer.java

/**
 * 创建一个扩展 AbstractSecurityWebApplicationInitializer 的一个类, 它将会自动地加载 springSecurityFilterChain<br/>
 * 相当于web.xml中的配置 <br/>
*  <filter>
        <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>
 */
public class SpringSecurityInitializer extends AbstractSecurityWebApplicationInitializer {

}

WebInit.java

/**
 * 相当于web.xml
 */
public class WebInit extends AbstractAnnotationConfigDispatcherServletInitializer {

    // 指定rootContext的配置类
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[] { AppConfig.class };
    }

    // 指定servletContext的配置类
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[] { MvcConfig.class };
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }
}

运行

tomcat7:run

URL权限控制

本案例没有使用springmvc,mybatis等框架。为了了解整体架构,尽可能使用默认配置。

数据库脚本

secuirty 默认表结构

可以根据需要修改

CREATE TABLE `users` (
  `username` varchar(50) NOT NULL,
  `password` varchar(50) NOT NULL,
  `enabled` tinyint(1) NOT NULL,
  PRIMARY KEY (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `authorities` (
  `username` varchar(50) NOT NULL,
  `authority` varchar(50) NOT NULL,
  UNIQUE KEY `ix_auth_username` (`username`,`authority`),
  CONSTRAINT `fk_authorities_users` FOREIGN KEY (`username`) REFERENCES `users` (`username`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;

新增表

CREATE TABLE `res` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(100) DEFAULT '',
  `url` varchar(500) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

CREATE TABLE `role_res` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `role` varchar(50) NOT NULL,
  `res_id` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `fk_res_id` (`res_id`),
  CONSTRAINT `fk_res_id` FOREIGN KEY (`res_id`) REFERENCES `res` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

数据

insert  into `users`(`username`,`password`,`enabled`) values ('admin','hoiAYbOZ504w7urYx6q5Ig==',1),('xiaoming','XgTEgTOg7jji7+37gvsX3g==',1);

insert  into `authorities`(`username`,`authority`) values ('admin','ADMIN'),('xiaoming','USER');

insert  into `res`(`id`,`name`,`url`) values (1,'首页','/index.jsp'),(2,'管理页','/admin.jsp');

insert  into `role_res`(`id`,`role`,`res_id`) values (1,'ADMIN',1),(2,'ADMIN',2),(3,'USER',1);

POM配置

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
    <!-- 日志 -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>jcl-over-slf4j</artifactId>
        <version>1.7.12</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.12</version>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-core</artifactId>
        <version>1.1.1</version>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.1.1</version>
    </dependency>

    <!-- spring security -->
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-web</artifactId>
        <version>3.1.6.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-config</artifactId>
        <version>3.1.6.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
    </dependency>

    <!-- mysql驱动-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.35</version>
    </dependency>
    <!-- 数据源  -->
    <dependency>
        <groupId>c3p0</groupId>
        <artifactId>c3p0</artifactId>
        <version>0.9.1.2</version>
    </dependency>
</dependencies>
<build>
    <finalName>sec-web</finalName>

    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.6.2</version>
            <configuration>
                <target>1.8</target>
                <source>1.8</source>
                <encoding>UTF-8</encoding>
            </configuration>
        </plugin>
    </plugins>
</build>

项目开发

页面

新建页面index.jsp、login.jsp、 loginError.jsp、 accessDenied.jsp、 admin.jsp

login.jsp内容, 其它页面略

<body>
	<form action="login.do" method="post">
		<table>
			<tr>
				<td>用户名:</td>
				<td><input type="text" name="username" /></td>
			</tr>
			<tr>
				<td>密码:</td>
				<td><input type="password" name="password" /></td>
			</tr>
			<tr>
				<td colspan="2" align="center">
				    <input type="submit" value="登录" />
				    <input type="reset" value="重置" /> 
				</td>
			</tr>
		</table>
	</form>
</body>

实体类

Res.java

private Integer id;
private String name;
private String url;
...

RoleRes.java

private Integer id;
private String role;
private Integer resId;
...

配置类

AuthenticationFailureHandlerImpl.java

@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
    response.sendRedirect(request.getContextPath() + "/loginError.jsp");
}

AuthenticationSuccessHandlerImpl.java

@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
    response.sendRedirect(request.getContextPath() + "/index.jsp");
}

UrlAccessDecisionManager.java

public class UrlAccessDecisionManager implements AccessDecisionManager {
    @Override
    public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)
            throws AccessDeniedException, InsufficientAuthenticationException {
        // 遍历角色
        for (ConfigAttribute ca : configAttributes) {
            // ① 当前url请求需要的权限
            String needRole = ca.getAttribute();
            if ("ROLE_LOGIN".equals(needRole)) {
                if (authentication instanceof AnonymousAuthenticationToken) {
                    throw new BadCredentialsException("未登录!");
                } else {
                    throw new AccessDeniedException("未授权该url!");
                }
            }

            // ② 当前用户所具有的角色
            Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
            for (GrantedAuthority authority : authorities) {
                // 只要包含其中一个角色即可访问
                if (authority.getAuthority().equals(needRole)) {
                    return;
                }
            }
        }
        throw new AccessDeniedException("请联系管理员分配权限!");

    }

    @Override
    public boolean supports(ConfigAttribute attribute) {
        return true;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return true;
    }
}

UrlFilterInvocationSecurityMetadataSource.java

public class UrlFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

    private JdbcDaoSupport dao;

    public void setDao(JdbcDaoSupport dao) {
        this.dao = dao;
    }

    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {

        // 获取当前请求url
        String requestUrl = ((FilterInvocation) object).getRequestUrl();
        // 忽略url请放在此处进行过滤放行
        List<String> paths = new ArrayList<>();
        paths.add("/login.jsp");
        paths.add("/loginError.jsp");
        if (paths.contains(requestUrl)) {
            return null;
        }

        // 数据库中所有url
        List<Res> resList = dao.getJdbcTemplate().query("select id,url from res ", new RowMapper<Res>() {
            @Override
            public Res mapRow(ResultSet rs, int rowNum) throws SQLException {
                Res res = new Res();
                res.setId(rs.getInt(1));
                res.setUrl(rs.getString(2));
                return res;
            }
        });
        for (Res res : resList) {
            // 获取该url所对应的权限
            if (requestUrl.equals(res.getUrl())) {
                List<RoleRes> roleResList = dao.getJdbcTemplate().query(
                        "SELECT id,role,res_id FROM role_res where res_id = ?", new Integer[] { res.getId() },
                        new RowMapper<RoleRes>() {
                            @Override
                            public RoleRes mapRow(ResultSet rs, int rowNum) throws SQLException {
                                RoleRes rr = new RoleRes();
                                rr.setId(rs.getInt(1));
                                rr.setRole(rs.getString(2));
                                rr.setResId(rs.getInt(3));
                                return rr;
                            }
                        });
                List<String> roles = new LinkedList<>();
                if (!CollectionUtils.isEmpty(roleResList)) {
                    for (RoleRes r : roleResList) {
                        roles.add("ROLE_" + r.getRole());
                    }
                }
                // 保存该url对应角色权限信息
                return SecurityConfig.createList(roles.toArray(new String[roles.size()]));
            }
        }
        // 如果数据中没有找到相应url资源则为非法访问,要求用户登录再进行操作
        return SecurityConfig.createList("ROLE_LOGIN");
    }

    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return FilterInvocation.class.isAssignableFrom(clazz);
    }
}

项目配置

连接数据库配置

基本信息

jdbc.properties

jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/test
jdbc.username=root
jdbc.password=mysql

Spring 连接数据库配置

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context 
		http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 加载基本信息 -->
	<context:property-placeholder location="classpath:jdbc.properties" />

	<!-- 数据库连接池 -->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<!-- 配置连接池属性 -->
		<property name="driverClass" value="${jdbc.driverClassName}" />
		<property name="jdbcUrl" value="${jdbc.url}" />
		<property name="user" value="${jdbc.username}" />
		<property name="password" value="${jdbc.password}" />
	</bean>

</beans>		

Spring Security配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:security="http://www.springframework.org/schema/security" 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">

	<security:http auto-config="false" entry-point-ref="authEntryPoint">
		<!-- 表示匿名用户可以访问 -->
		<security:intercept-url pattern="/login.jsp" access="IS_AUTHENTICATED_ANONYMOUSLY" />

		<!-- 改变默认登出URL(/j_spring_security_logout,此URL失效) 为 /logout -->
		<security:logout delete-cookies="JSESSIONID" logout-url="/logout" />
		<!-- 添加自定义的AuthenticationFilter到FilterChain的FORM_LOGIN_FILTER位置 -->
		<security:custom-filter ref="authenticationFilter" position="FORM_LOGIN_FILTER" />
		<!-- 异常处理 -->
		<security:custom-filter ref="exceptionTranslationFilter" after="EXCEPTION_TRANSLATION_FILTER" />
		<!--  -->
		<security:custom-filter ref="filterSecurityInterceptor" before="FILTER_SECURITY_INTERCEPTOR" />
	</security:http>

	<!-- AuthenticationEntryPoint,引导用户进行登录 -->
	<bean id="authEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
		<property name="loginFormUrl" value="/login.jsp" />
	</bean>

	<bean id="exceptionTranslationFilter" class="org.springframework.security.web.access.ExceptionTranslationFilter">
		<property name="authenticationEntryPoint" ref="authEntryPoint" />
		<property name="accessDeniedHandler">
			<bean class="org.springframework.security.web.access.AccessDeniedHandlerImpl">
				<property name="errorPage" value="/accessDenied.jsp" />
			</bean>
		</property>
	</bean>

	<!-- 认证过滤器 -->
	<bean id="authenticationFilter"
		class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
		<property name="authenticationManager" ref="authenticationManager" />
		<property name="usernameParameter" value="username" />
		<property name="passwordParameter" value="password" />
		<!-- 改变默认登录URL(/j_spring_security_check,此URL失效) 为 /login.do -->
		<property name="filterProcessesUrl" value="/login.do" />
		<property name="authenticationSuccessHandler" ref="authenticationSuccessHandler" />
		<property name="authenticationFailureHandler" ref="authenticationFailureHandler" />
	</bean>

	<bean id="authenticationSuccessHandler" class="com.demo.security.config.AuthenticationSuccessHandlerImpl" />
	<bean id="authenticationFailureHandler" class="com.demo.security.config.AuthenticationFailureHandlerImpl" />

	<!-- 用于认证的AuthenticationManager -->
	<security:authentication-manager alias="authenticationManager">
		<security:authentication-provider user-service-ref="userDetailsService">
			<security:password-encoder hash="md5" base64="true">
				<security:salt-source user-property="username" />
			</security:password-encoder>
		</security:authentication-provider>
	</security:authentication-manager>

	<bean id="userDetailsService" class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
		<property name="dataSource" ref="dataSource" />
		<property name="rolePrefix" value="ROLE_" />
	</bean>

	<!-- 获取所配置资源访问的授权信息 -->
	<bean id="filterSecurityInterceptor"
		class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
		<property name="authenticationManager" ref="authenticationManager" />
		<property name="accessDecisionManager" ref="accessDecisionManager" />
		<property name="securityMetadataSource" ref="filterInvocationSecurityMetadataSource" />
	</bean>

	<bean id="accessDecisionManager" class="com.demo.security.config.UrlAccessDecisionManager" />
	<bean id="filterInvocationSecurityMetadataSource"
		class="com.demo.security.config.UrlFilterInvocationSecurityMetadataSource">
		<property name="dao" ref="userDetailsService" />
	</bean>
</beans>

Web配置

   <context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:spring/applicationContext.xml,classpath:spring/spring-security.xml</param-value>
	</context-param>

	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
	
	<listener>
		<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
	</listener>

	<filter>
		<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>
	
	<welcome-file-list>
		<welcome-file>index.jsp</welcome-file>
	</welcome-file-list>

自定义过滤器链

web.xml 配置DelegatingFilterProxy 代理,spring-security.xml里通过FilterChainProxy配置具体的过滤器类。

pom.xml引用

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
    <!-- 日志 -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>jcl-over-slf4j</artifactId>
        <version>1.7.12</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.12</version>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-core</artifactId>
        <version>1.1.1</version>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.1.1</version>
    </dependency>

    <!-- spring security -->
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-web</artifactId>
        <version>3.1.6.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-config</artifactId>
        <version>3.1.6.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
    </dependency>

</dependencies>
<build>
    <finalName>security-filter</finalName>

    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.6.2</version>
            <configuration>
                <target>1.8</target>
                <source>1.8</source>
                <encoding>UTF-8</encoding>
            </configuration>
        </plugin>
    </plugins>
</build>

web.xml配置

<web-app id="webId" version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

	<display-name>Archetype Created Web Application</display-name>
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:spring/spring-security.xml</param-value>
	</context-param>

	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

	<filter>
		<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>

	<welcome-file-list>
		<welcome-file>index.jsp</welcome-file>
	</welcome-file-list>
</web-app>

spring-security.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:security="http://www.springframework.org/schema/security" 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">

	<bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">
		<security:filter-chain-map path-type="ant">
			<security:filter-chain pattern="/**"
				filters="httpSessionContextFilter, logoutFilter, authenticationFilter, anonymousAuthenticationFilter, exceptionTranslationFilter, filterSecurityInterceptor" />
		</security:filter-chain-map>
	</bean>

	<bean id="httpSessionContextFilter"
		class="org.springframework.security.web.context.SecurityContextPersistenceFilter" />

	<bean id="logoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
		<constructor-arg value="/logout.jsp" />
		<constructor-arg>
			<bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler" />
		</constructor-arg>
		<property name="filterProcessesUrl" value="/logout" />
	</bean>

	<!-- 认证过滤器 -->
	<bean id="authenticationFilter"
		class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
		<property name="authenticationManager" ref="authenticationManager" />
		<property name="usernameParameter" value="username" />
		<property name="passwordParameter" value="password" />
		<!-- 改变默认登录URL(/j_spring_security_check,此URL失效) 为 /login.do -->
		<property name="filterProcessesUrl" value="/login.do" />
		<property name="authenticationSuccessHandler" ref="authenticationSuccessHandler" />
		<property name="authenticationFailureHandler" ref="authenticationFailureHandler" />
	</bean>

	<bean id="authenticationSuccessHandler" class="com.demo.security.config.AuthenticationSuccessHandlerImpl" />
	<bean id="authenticationFailureHandler" class="com.demo.security.config.AuthenticationFailureHandlerImpl" />

	<!-- 用于认证的AuthenticationManager -->
	<security:authentication-manager alias="authenticationManager">
		<security:authentication-provider>
			<security:user-service>
				<security:user name="admin" password="123" authorities="ROLE_USER,ROLE_ADMIN" />
				<security:user name="xiaoming" password="123" authorities="ROLE_USER" />
			</security:user-service>
		</security:authentication-provider>
	</security:authentication-manager>

	<bean id="anonymousAuthenticationFilter"
		class="org.springframework.security.web.authentication.AnonymousAuthenticationFilter">
		<constructor-arg value="123" />
	</bean>

	<bean id="exceptionTranslationFilter" class="org.springframework.security.web.access.ExceptionTranslationFilter">
		<property name="authenticationEntryPoint" ref="authEntryPoint" />
		<property name="accessDeniedHandler">
			<bean class="org.springframework.security.web.access.AccessDeniedHandlerImpl">
				<property name="errorPage" value="/accessDenied.jsp" />
			</bean>
		</property>
	</bean>

	<!-- AuthenticationEntryPoint,引导用户进行登录 -->
	<bean id="authEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
		<property name="loginFormUrl" value="/login.jsp" />
	</bean>

	<!-- 获取所配置资源访问的授权信息 -->
	<bean id="filterSecurityInterceptor"
		class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
		<property name="authenticationManager" ref="authenticationManager" />
		<property name="accessDecisionManager" ref="accessDecisionManager" />
		<property name="securityMetadataSource">
			<security:filter-security-metadata-source>
				<security:intercept-url pattern="/log**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
				<security:intercept-url pattern="/admin**" access="ROLE_ADMIN" />
				<security:intercept-url pattern="/**" access="ROLE_USER" />
			</security:filter-security-metadata-source>
		</property>
	</bean>
	
	<bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
		<property name="decisionVoters">
			<list>
				<bean class="org.springframework.security.access.vote.RoleVoter">
					<property name="rolePrefix" value="" />
				</bean>
				<bean class="org.springframework.security.access.vote.AuthenticatedVoter" />
			</list>
		</property>
	</bean>
	
</beans>

Java类

AuthenticationFailureHandlerImpl.java

public class AuthenticationFailureHandlerImpl implements AuthenticationFailureHandler {
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
            AuthenticationException exception) throws IOException, ServletException {
        response.sendRedirect(request.getContextPath() + "/loginError.jsp");
    }
}

AuthenticationSuccessHandlerImpl.java

public class AuthenticationSuccessHandlerImpl implements AuthenticationSuccessHandler {
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        response.sendRedirect(request.getContextPath() + "/index.jsp");
    }
}

页面

accessDenied.jsp、admin.jsp、index.jsp、login.jsp、loginError.jsp

login.jsp如下,其它略

<body>
	<form action="login.do" method="post">
		<table>
			<tr>
				<td>用户名:</td>
				<td><input type="text" name="username" /></td>
			</tr>
			<tr>
				<td>密码:</td>
				<td><input type="password" name="password" /></td>
			</tr>
			<tr>
				<td colspan="2" align="center">
				    <input type="submit" value="登录" />
				    <input type="reset" value="重置" /> 
				</td>
			</tr>
		</table>
	</form>
</body>
posted @ 2022-07-28 21:16  Saltery  阅读(210)  评论(0)    收藏  举报