在使用Spring Security之前首先要有个spring的web项目,这里不再多说。
<dependency>
<groupId>org.springframework.securitygroupId>
<artifactId>spring-security-webartifactId>
<version>4.0.2.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframework.securitygroupId>
<artifactId>spring-security-configartifactId>
<version>4.0.2.RELEASEversion>
dependency>
<filter>
<filter-name>springSecurityFilterChainfilter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxyfilter-class>
filter>
<filter-mapping>
<filter-name>springSecurityFilterChainfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
这里是写死的两个用户名密码,下面注释掉的是从数据库取数据验证的
<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">
<intercept-url pattern="/login.jsp" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<intercept-url pattern="/**" access="ROLE_USER" />
<form-login login-page='/login.jsp' authentication-failure-url='/login.jsp?error' default-target-url="/index.jsp" />
<logout />
<csrf disabled="true" />
<custom-filter ref="authenticationFilter" before="FORM_LOGIN_FILTER" />
http>
<beans:bean id="authenticationFilter" class="com.snow.security4.controller.TestLoginFilter">
<beans:property name="filterProcessesUrl" value="/login" />
<beans:property name="authenticationManager" ref="authenticationManager" />
beans:bean>
<authentication-manager alias="authenticationManager">
<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:bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<beans:property name="driverClassName" value="com.mysql.jdbc.Driver" />
<beans:property name="url" value="jdbc:mysql://localhost:3306/CTB?serverTimezone=GMT" />
<beans:property name="username" value="mzh" />
<beans:property name="password" value="mzh" />
beans:bean>
beans:beans>
经过上面的配置,启动服务器,用浏览器打开这个Web应用的任意一个页面,都会跳转到一个登录页,这个登录页面是Spring Security自动生成的。
输入写死的那俩用户名密码即可登录成功。
TestLoginFilter类是个过滤器,如上配置,实在每次spring security做验证之前都会先经过,这个过滤器。也可以改成after,就是验证之后经过。
package com.snow.security4.controller;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Created by mazhenhua on 2017/3/20.
*/
public class TestLoginFilter extends UsernamePasswordAuthenticationFilter {
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
System.out.println("就是你了");
return super.attemptAuthentication(request, response);
}
}
一个比较简单的方法是:
<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 ctb.user_info WHERE username = ?" />
<beans:property name="authoritiesByUsernameQuery" value="SELECT username, usertype true FROM ctb.user_info WHERE username = ?;" />
beans:bean>
直接把读密码和用户民权限的sql,丢进来,会直接读的,
复杂一点的验证,需要实现一个接口org.springframework.security.core.userdetails.UserDetailsService
public class UserDetailsServiceImpl implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 以下可以替换成用其他方式获取用户信息
if(username.equals("xxg")) {
Collection auths = new ArrayList();
SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_USER");
auths.add(authority);
User user = new User(username, "123456", auths);
return user;
} else {
throw new UsernameNotFoundException("用户不存在");
}
}
}
然后再配置文件中配
<authentication-manager>
<authentication-provider user-service-ref='userDetailsService' />
authentication-manager>
<beans:bean id="userDetailsService" class="com.snow.security4.controller.UserDetailsServiceImpl" />
明文保存密码通常是不安全的,在Spring Security中可以配置密码的加密方法。下面以MD5加密密码为例。
针对密码加密,Spring Security提供了org.springframework.security.crypto.password.PasswordEncoder接口。我们需要实现PasswordEncoder接口,实现我们自定义的加密方法,这样Spring Security在接收到用户登录请求后,会调用这个实现类,从而判断密码是否正确:
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);
}
}
配置文件:
<authentication-manager>
<authentication-provider>
<password-encoder ref="passwordEncoder" />
authentication-provider>
authentication-manager>
<beans:bean id="passwordEncoder" class="com.snow.security4.controller.PasswordEncoderImpl" />
目前很多网站登录时都有“记住我”、“下次自动登录”这样的chechbox,用户登录成功后下次再访问网站就不需要重复登录,对用户来说非常方便。这个功能在Spring Security中实现起来非常简单。
首先,你需要在html上写一个checkbox,name为 remember-me
<input type="checkbox" id="keep-login" name="remember-me"><label for="keep-login">Remember Melabel>
然后在Spring Security配置文件中加入:
<http use-expressions="false">
// 如果之前配置http标签,这里只将remember-me放进去就好了
<remember-me />
http>
默认的Remember Me有效时间时14天,还可以通过token-validity-seconds属性自定义有效时长(单位:秒)
如果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"/>
Spring Security默认启用CSRF防御,要求每个POST请求都要都要带上CSRF token参数,如果感觉比较麻烦或者网站安全性要求不高,可以配置禁用:
<http use-expressions="false">
// 如果之前配置http标签,这里只将remember-me放进去就好了
<csrf disabled="true" />
http>
// 获取用户名
httpServletRequest.getRemoteUser(); // Servlet标准,推荐使用
SecurityContextHolder.getContext().getAuthentication().getName();
// 获取用户ROLE:
SecurityContextHolder.getContext().getAuthentication().getAuthorities();
// 判断用户是否拥有ROLE:
httpServletRequest.isUserInRole("ADMIN");