步骤一:新建工程
新建一个maven工程,并使用以下依赖:或者去下载Spring Security 的jar包
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>4.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>4.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>4.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>4.2.2.RELEASE</version>
</dependency>
Spring Security(以下简称SS) 3 和 4 版本差异很大,这里我用的是SS4。如果搭配spring 使用,则对spring 版本也有要求,尽量用新的就行,这里我用的spring 4.2.4
步骤二:配置web.xml
Spring Security 的原理是使用了过滤器,所以我们配置SS的过滤器,好让它生效。
<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系的配置文件一起加载,使用如下配置
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/applicationContext*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
这是我项目结构图,applicationContext-security.xml是SS的配置文件
步骤四:编写配置文件
首先先看我自己工程中的配置文件
<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 pattern="/**/*.js" security="none" />
<http pattern="/**/*.css" security="none" />
<http use-expressions="true">
<!-- 访问所有页面都需要有USER权限 -->
<intercept-url pattern="/login.html" access="hasRole('ROLE_ANONYMOUS') or hasRole('ROLE_USER')" />
<intercept-url pattern="/index.html" access="hasRole('ROLE_ANONYMOUS') or hasRole('ROLE_USER')" />
<intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
<!-- 登录功能 -->
<form-login login-page="/login.html" default-target-url="/index.html" authentication-failure-url="/login.html?error=true" always-use-default-target="true" />
<!-- 配置登录页面地址login-page、登录失败后的跳转地址authentication-failure-url -->
<!-- <form-login login-page='/login.jsp' authentication-failure-url='/login.jsp?error' />-->
<!-- 登出功能 -->
<logout logout-url="/logout" />
<csrf disabled="true"/>
</http>
<!--
<authentication-manager>
<authentication-provider>
<user-service>
<user name="jimi" password="jimi" authorities="ROLE_USER" />
<user name="bob" password="bob" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
-->
<!-- Select users and user_roles from database -->
<authentication-manager>
<authentication-provider>
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query="select user_id username,password password, enabled enabled from users where user_id=?"
authorities-by-username-query="select user_id username, rightstr role from privilege where user_id=? " />
<password-encoder hash="md5">
</password-encoder>
</authentication-provider>
</authentication-manager>
</beans:beans>
<http pattern="/**/*.js" security="none" />
表示对以.js后缀的文件完全放行,注意,是完全放行,不经过过滤器。推荐把一些静态文件用这种写法,因为如果将主页之类文件的security 置为none,将不会经过SS的过滤器,
进而无法在页面上取出任何值。(当前登录用户,当前权限等等)
<http use-expressions="true">
意思为开启
SpEL(SS自定义的一种表达式语言),开启之后access里都要写成我上述的写法
<intercept-url pattern="/login.html" access="hasRole('ROLE_ANONYMOUS') or hasRole('ROLE_USER')" />
表示login.html这个页面只有匿名用户和User权限的用户才能访问。
如果不开启SpEL,可以这样写:
<intercept-url pattern="/login.html" access="ROLE_ANONYMOUS,ROLE_USER" />
我这几条的意思是,除了login.html以及index.html做了特殊处理(允许匿名用户访问),其他都要求ROLE_USER权限
<!-- 访问所有页面都需要有USER权限 -->
<intercept-url pattern="/login.html" access="hasRole('ROLE_ANONYMOUS') or hasRole('ROLE_USER')" />
<intercept-url pattern="/index.html" access="hasRole('ROLE_ANONYMOUS') or hasRole('ROLE_USER')" />
<intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
登陆配置:
<form-login login-page="/login.html" default-target-url="/index.html" authentication-failure-url="/login.html?error=true" always-use-default-target="true" />
依次是,登陆页面的地址,登陆完跳转的地址,登陆失败时跳转的地址,是否在登陆成功后一直跳转到登陆成功页面(如果不开启,SS默认跳转到用户在登陆前正在浏览时因为权限不足被弹出来的页面)
登出路径配置:还有其他配置选项,我没有配,就配了路径
<logout logout-url="/logout" />
是否关闭防止csrf攻击:
<csrf disabled="true"/>
如果不关闭,每次post请求必须附带一个token。因为我嫌麻烦直接关掉了
这是登陆管理器:
<authentication-manager>
<authentication-provider>
<user-service>
<user name="lynn" password="lynn" authorities="ROLE_USER" />
<user name="bob" password="bob" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
如果不适用数据库做账号密码验证,可以把用户密码和拥有的权限填在这儿,但估计没人会这么做。
接下来介绍数据库式的:
<!-- Select users and user_roles from database -->
<authentication-manager>
<authentication-provider>
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query="select user_id username,password password, enabled enabled from users where user_id=?"
authorities-by-username-query="select user_id username, rightstr role from privilege where user_id=? " />
<password-encoder hash="md5">
</password-encoder>
</authentication-provider>
</authentication-manager>
这里需要配置一个authentication-provider,然后需要注入一个dataSource,这个是你的连接池的bean。我没有定义在这个配置文件中,你可以另外开一个applicationContext-dao 放连接池,我用的Druid连接池
<!-- 数据库连接池 -->
<!-- 加载配置文件 -->
<context:property-placeholder location="classpath:conf/db.properties" />
<!-- 数据库连接池 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
destroy-method="close">
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="driverClassName" value="${jdbc.driver}" />
<property name="maxActive" value="10" />
<property name="minIdle" value="5" />
</bean>
<!-- 让spring管理sqlsessionfactory 使用mybatis和spring整合包中的 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 数据库连接池 -->
<property name="dataSource" ref="dataSource" />
<!-- 加载mybatis的全局配置文件 -->
<property name="configLocation" value="classpath:mybatis/SqlMapConfig.xml" />
</bean>
下面是sql查询语句:
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query="select user_id username,password password, enabled enabled from users where user_id=?"
authorities-by-username-query="select user_id username, rightstr role from privilege where user_id=? " />
特别注意:账号列如果不是username,请起一个别名username,否则SS无法识别,同理,password和enabled也是
<password-encoder hash="md5">
采用了md5加密,开启这个从前台传过来的密码SS会经过一次md5加密,然后跟数据库里的密码进行比对。也有其他加密方式,官方推荐使用bcrypt,这里我用了md5
步骤五:更改前台表单
<h1 class="text-center" style="margin-bottom: 30px">用户登录</h1>
<form class="form-horizontal caption" action="login" method="post">
<div class="form-group">
<label for="username" class="col-sm-3 control-label">用户名</label>
<div class="col-sm-8">
<input type="text" class="form-control" id="username" placeholder="用户名">
</div>
</div>
<div class="form-group">
<label for="password" class="col-sm-3 control-label">密码</label>
<div class="col-sm-8">
<input type="password" class="form-control" id="password" placeholder="密码">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<div class="checkbox">
<label>
<input type="checkbox">记住我
</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-4 col-sm-5">
<button type="submit" class="btn btn-success btn-block">登录</button>
</div>
</div>
</form>
前台我用的bootstrap,这是登陆表单的代码,需要把用户名框的name设为username,把密码框的name设为password,这样SS才能检测到。表单提交的路径是SS 默认的login
步骤六:启动工程测试
当我访问problem.html时,被弹到了登陆页面,但访问index.html能正常访问(因为设置了匿名访问权限)
登陆成功:
关于如何在页面上取到当前用户信息,看我接下来的文章