在使用Spring Security配置Web应用之前,首先要准备一个基于Maven的Spring框架创建的Web应用(Spring MVC不是必须的),本文的内容都是基于这个前提下的。

pom.xml添加依赖

除了Spring框架本身的一些依赖包,还需要在pom.xml中添加Spring Security的依赖包:

1
2
3
4
5
6
7
8
9
10
<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

1
2
3
4
5
6
7
8
<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中。下面是一个最基本的Spring Security配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<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自动生成的。
Spring
Security默认登录页面

在登录页面输入错误的用户名密码,就会登录失败并有提示。输入正确的用户名密码,则登录成功,就可以进入Web应用的页面。一个最简单的基于Spring Security的Web应用已经完成!

指定登录页面

由于Spring Security默认的登录页面非常简陋,一般不会直接使用,通常会指定一个自定义的登录页面,例如指定一个自己的登录页/login.jsp

1
2
3
4
5
6
7
8
9
10
<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中的登录表单:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<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请求,登录请求需要提交usernamepassword两个参数。为了安全,防止恶意的CSRF攻击,Spring Security需要校验form表单中的hidden域提交的内容。

登出

Spring Security配置文件中的<logout />用于处理登出。

页面中的登出按钮:

1
2
3
4
5
<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语句就能从数据库获取到用户信息:

1
2
3
4
5
6
7
8
<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>

以上配置还可以简化为:

1
2
3
4
5
6
7
<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方法,即通过用户名获取用户信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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配置文件中:

1
2
3
4
<authentication-manager>
<authentication-provider user-service-ref='userDetailsService' />
</authentication-manager>
<beans:bean id="userDetailsService" class="com.xxg.UserDetailsServiceImpl" />

密码加密

明文保存密码通常是不安全的,在Spring Security中可以配置密码的加密方法。下面以MD5加密密码为例。

针对密码加密,Spring Security提供了org.springframework.security.crypto.password.PasswordEncoder接口。我们需要实现PasswordEncoder接口,实现我们自定义的加密方法,这样Spring Security在接收到用户登录请求后,会调用这个实现类,从而判断密码是否正确:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class PasswordEncoderImpl implements PasswordEncoder {

@Override
public String encode(CharSequence rawPassword) {
try {
// MD5加密密码
return DigestUtils.md5DigestAsHex(rawPassword.toString().getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return null;
}
}

@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
return encode(rawPassword).equals(encodedPassword);
}
}

在Spring Security配置文件中配置上面的实现类:

1
2
3
4
5
6
7
<authentication-manager>
<authentication-provider>
<password-encoder ref="passwordEncoder" />
...
</authentication-provider>
</authentication-manager>
<beans:bean id="passwordEncoder" class="com.xxg.PasswordEncoderImpl" />

配置不受Spring Security管理的URL

如果Web应用中有某些URL不需要被Spring Security管理,例如一些静态文件,或者无需登录即可查看的页面,可以对这些URL配置security="none"

1
2
3
4
5
6
7
8
<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>

禁用CSRF防御

Spring Security默认启用CSRF防御,要求每个POST请求都要都要带上CSRF token参数,如果感觉比较麻烦或者网站安全性要求不高,可以配置禁用:

1
2
3
4
<http use-expressions="false">
...
<csrf disabled="true" />
</http>

获取登录用户信息

获取用户名:

1
2
httpServletRequest.getRemoteUser();  // Servlet标准,推荐使用
SecurityContextHolder.getContext().getAuthentication().getName();

获取用户ROLE:

1
SecurityContextHolder.getContext().getAuthentication().getAuthorities();

判断用户是否拥有ROLE:

1
httpServletRequest.isUserInRole("ADMIN");

Spring Security Web应用入门环境搭建的更多相关文章

  1. Spring MVC+Spring+Mybatis+MySQL(IDEA)入门框架搭建

    目录 Spring MVC+Spring+Mybatis+MySQL(IDEA)入门框架搭建 0.项目准备 1.数据持久层Mybatis+MySQL 1.1 MySQL数据准备 1.2 Mybatis ...

  2. ArcGIS API for Silverlight/ 开发入门 环境搭建

    Silverlight/ 开发入门 环境搭建1 Silverlight SDK下载ArcGIS API for Microsoft Silverlight/WPF ,需要注册一个ESRI Gloab ...

  3. spring-security-4 (2)spring security 基于Java配置的搭建

    一.spring security的模块 搭建spring security首先我们要导入必须的jar,即maven的依赖.spring security按模块划分,一个模块对应一个jar. spri ...

  4. Windows C#入门环境搭建

    Windows C#入门环境搭建 1. 安装Microsoft .NET Framework目录: C:\Windows\Microsoft.NET\Framework,查看已经安装的版本. 如果未安 ...

  5. Android开发使用控件入门--环境搭建

    Android开发使用控件入门--环境搭建 软件名称(,梦,,想.CAD  ,控件) 1. 环境搭建: 3 1.1. 安装Eclipse 3 1.2. 下载JDK 3 1.3. 下载Android S ...

  6. 57.NodeJS入门--环境搭建 IntelliJ IDEA

    转自:https://blog.csdn.net/wang19891106/article/details/51127133 NodeJS入门–环境搭建 IntelliJ IDEA 本人也刚开始学习N ...

  7. NodeJS入门--环境搭建 IntelliJ IDEA

    NodeJS入门–环境搭建 IntelliJ IDEA 本人也刚开始学习NodeJS,所以以此做个笔记,欢迎大家提出意见. 1.首先 下载安装NodeJS,下载安装IntelliJ IDEA 2.接下 ...

  8. Spring Security极简入门三部曲(上篇)

    目录 Spring Security极简入门三部曲(上篇) 写在前面 为什么要用Spring Security 数据库设计 demo时刻 核心代码讲解 小结 Spring Security极简入门三部 ...

  9. Spring Security极简入门三部曲(中篇)

    目录 Spring Security极简入门三部曲(中篇) 验证流程 Authentication接口 过滤器链 AuthenticationProvider接口: demo时刻 代码讲解 小结 Sp ...

随机推荐

  1. 数据库MySQL--条件查询/排序查询

    一.条件查询 条件查询:满足条件的字段被筛选出来 语法:select 查询列表字段 from 表名 where 筛选条件: 条件查询的条件分类: 1.按条件表达式筛选:条件运算符:>, < ...

  2. Gamma(1)

    目前为止看到的解释Gamma来由说得最清楚的一篇文章:https://www.cambridgeincolour.com/tutorials/gamma-correction.htm 几点总结. 1, ...

  3. thinkphp 切换数据库

    除了在预先定义数据库连接和实例化的时候指定数据库连接外,我们还可以在模型操作过程中动态的切换数据库,支持切换到相同和不同的数据库类型.用法很简单, 只需要调用Model类的db方法,用法: 常州大理石 ...

  4. thinkphp 操作绑定到类

    定义 ThinkPHP3.2版本提供了把每个操作方法定位到一个类的功能,可以让你的开发工作更细化,可以设置参数ACTION_BIND_CLASS,例如: 'ACTION_BIND_CLASS' =&g ...

  5. LOJ#6437. 「PKUSC2018」PKUSC

    题面 题意转化为: 判断每个点所在的圆有多长的弧度角位于多边形内部. 然后就很暴力了. 每个点P,直接找到多边形和这个圆的所有交点,按照距离P的角度排序. 找交点,直接联立二元二次方程组.... 需要 ...

  6. selenium python bindings 元素定位

    1. 辅助 Firepath Firefox是所有做前端的必不可少的浏览器因为firebug的页面元素显示很清晰.用selenium 去定位元素的时候Firefox还有一个非常友好的工具就是firep ...

  7. STM32F103 Feature

  8. Mysql配置innodb_flush_log_at_trx_commit

    当innodb_flush_log_at_trx_commit被 设置为0,日志缓冲每秒一次地被写到日志文件,并且对日志文件做到磁盘操作的刷新,但是在一个事务提交不做任何操作.当这个值为1(默认值)之 ...

  9. JavaScript开发人员必知的10个关键习惯

    还在一味没有目的的编写JavaScript代码吗?那么你就OUT了!让我们一起来看看小编为大家搜罗的JavaScript开发人员应该具备的十大关键习惯吧! 随着新技术的不断发展,JavaScript已 ...

  10. Java基础拾遗(二) — 关于equals(),hashcode()和 ==

    这里分别讲==和equals()的关系,以及equals()和hashcode()的关系 讲解之前,需要先明白对象的内容.对象的引用,基本类型,引用类型这几个概念,此处不做解释 一.==和equals ...