在使用Spring Security配置Web应用之前,首先要准备一个基于Maven的Spring框架创建的Web应用(Spring MVC不是必须的),本文的内容都是基于这个前提下的。
pom.xml添加依赖
除了Spring框架本身的一些依赖包,还需要在pom.xml中添加Spring Security的依赖包:
<dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>4.0.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>4.0.2.RELEASE</version> </dependency>
入门环境配置
要想使用Spring Security,首先需要在web.xml配置一个过滤器,注意过滤器的filter-name必须是"springSecurityFilterChain":
<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>
另外还需要配置Spring Security配置文件,并将这个文件添加到Spring Application Context中:
<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 use-expressions="false"> <!-- 访问所有页面都需要有USER权限 --> <intercept-url pattern="/**" access="ROLE_USER" /> <!-- 登录功能 --> <form-login /> <!-- 登出功能 --> <logout /> </http> <authentication-manager> <authentication-provider> <user-service> <!-- 这里创建两个用户,可以通过用户名密码登录 --> <user name="jimi" password="jimispassword" authorities="ROLE_USER, ROLE_ADMIN" /> <user name="bob" password="bobspassword" authorities="ROLE_USER" /> </user-service> </authentication-provider> </authentication-manager> </beans:beans>
只需完成以上两个配置,启动服务器,用浏览器打开这个Web应用的任意一个页面,都会跳转到一个登录页,这个登录页面时Spring Security自动生成的。
在登录页面输入错误的用户名密码,就会登录失败并有提示。输入正确的用户名密码,则登录成功,就可以进入Web应用的页面。一个最简单的基于Spring Security的Web应用已经完成!
指定登录页面
由于Spring Security默认的登录页面非常简陋,一般不会直接使用,通常会指定一个自定义的登录页面:
<http use-expressions="false"> <!-- 登录页面不需要控制权限 --> <intercept-url pattern="/login.jsp*" access="IS_AUTHENTICATED_ANONYMOUSLY"/> <!-- 访问其他所有页面都需要有USER权限 --> <intercept-url pattern="/**" access="ROLE_USER" /> <!-- 配置登录页面地址login-page、登录失败后的跳转地址authentication-failure-url --> <form-login login-page=‘/login.jsp‘ authentication-failure-url=‘/login.jsp?error‘ /> <!-- 登出功能 --> <logout /> </http>
自定义的登录页面jsp中的登录表单:
<c:url value="/login" var="loginUrl" /> <form action="${loginUrl}" method="post"> <c:if test="${param.error != null}"> <p>Invalid username and password.</p> </c:if> <c:if test="${param.logout != null}"> <p>You have been logged out.</p> </c:if> <p> <label for="username">Username</label> <input type="text" id="username" name="username" /> </p> <p> <label for="password">Password</label> <input type="password" id="password" name="password" /> </p> <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" /> <button type="submit" class="btn">Log in</button> </form>
登录表单提交的页面地址是/login,method是POST请求。为了安全,防止恶意的CSRF攻击,Spring Security需要校验form表单中的hidden域提交的内容。
登出
配置文件中的<logout />用于处理登出。
页面中的登出按钮:
<c:url value="/logout" var="logoutUrl" /> <form action="${logoutUrl}" method="post"> <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" /> <input type="submit" value="退出" /> </form>
登出请求地址/logout,method是POST请求。
登录用户信息从数据库获取
上文的登录用户的用户名、密码、ROLE都是配置在Spring Security的xml配置文件中的,在实际使用中,一般不会将用户信息直接配置在xml文件中,而是通过其他方式获取,例如数据库。
Spring Security提供了一个便捷的方式通过数据库获取用户信息,即org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl,它是org.springframework.security.core.userdetails.UserDetailsService接口的一个实现类,只要配置相关的DataSource和SQL语句就能从数据库获取到用户信息:
<authentication-manager> <authentication-provider user-service-ref=‘userDetailsService‘ /> </authentication-manager> <beans:bean id="userDetailsService" class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl"> <beans:property name="dataSource" ref="dataSource"/> <beans:property name="usersByUsernameQuery" value="select username, password, true from t_user where username = ?" /> <beans:property name="authoritiesByUsernameQuery" value="select username, role from t_user_role where username = ?" /> </beans:bean>
以上配置还可以简化为:
<authentication-manager> <authentication-provider> <jdbc-user-service data-source-ref="dataSource" users-by-username-query="select username, password, true from t_user where username = ?" authorities-by-username-query="select username, role from t_user_role where username = ?" /> </authentication-provider> </authentication-manager>
登录用户信息通过其他方式获取
如果用户信息的来源并不是数据库,那么就需要自己实现org.springframework.security.core.userdetails.UserDetailsService接口的loadUserByUsername方法,即通过用户名获取用户信息:
public class UserDetailsServiceImpl implements UserDetailsService { @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { // 以下可以替换成用其他方式获取用户信息 if(username.equals("xxg")) { Collection<GrantedAuthority> auths = new ArrayList<GrantedAuthority>(); SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_USER"); auths.add(authority); User user = new User(username, "123456", auths); return user; } else { throw new UsernameNotFoundException("用户不存在"); } } }
将该实现类配置在Spring Security配置文件中:
<authentication-manager> <authentication-provider user-service-ref=‘userDetailsService‘ /> </authentication-manager> <beans:bean id="userDetailsService" class="com.xxg.service.UserDetailsServiceImpl" />
配置不受Spring Security管理的URL
如果Web应用中有某些URL不需要被Spring Security管理,例如一些静态文件,或者无需登录即可查看的页面,可以对这些URL配置security="none":
<http pattern="/resources/css/**" security="none"/> <http pattern="/resources/images/**" security="none"/> <http pattern="/resources/js/**" security="none"/> <http use-expressions="false"> <intercept-url pattern="/**" access="ROLE_USER" /> <form-login /> <logout /> </http>
获取登录用户信息
获取用户名:
httpServletRequest.getRemoteUser(); // Servlet标准,推荐使用 SecurityContextHolder.getContext().getAuthentication().getName();
获取用户ROLE:
SecurityContextHolder.getContext().getAuthentication().getAuthorities();
判断用户是否拥有ROLE:
httpServletRequest.isUserInRole("ADMIN");
版权声明:本文为博主原创文章,未经博主允许不得转载。