SpringSecurity5.0.8入门:密码加密,自定义登录页面
一、什么是SpringSecurity
Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。
二、SpringSecurity入门小demo
1、创建maven工程
2、编辑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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cheng.demo.springsecurity</groupId>
<artifactId>spring-security-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<spring.version>5.0.8.RELEASE</spring.version>
<security.version>5.0.8.RELEASE</security.version>
</properties>
<dependencies>
<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>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${security.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- java编译插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<configuration>
<!-- 指定端口 -->
<port>9090</port>
<!-- 请求路径 -->
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>
</project>
3、创建WEB-INF文件夹和web.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
id="WebApp_ID" version="4.0">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-security.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<!-- 过滤器名字必须是 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>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.jsp</welcome-file>
<welcome-file>default.htm</welcome-file>
</welcome-file-list>
</web-app>
4、创建spring-security.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<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="/login.html" security="none"></http>
<http pattern="/error.html" security="none"></http>
<http pattern="/js/**" security="none"></http>
<http use-expressions="false">
<!-- 页面拦截规则 必须以ROLE_开头 hasRole('ROLE_USER') -->
<intercept-url pattern="/**" access="ROLE_USER" />
<!-- 开启表单登录功能 定义登录页面、成功和失败跳转页面-->
<form-login login-page="/login.html"
default-target-url="/index.html"
authentication-failure-url="/login.html" />
<!-- 关闭csrf 一个token认证-->
<csrf disabled="true" />
<!-- 允许iframe -->
<headers>
<frame-options policy="SAMEORIGIN" />
</headers>
<logout />
</http>
<authentication-manager>
<!-- 认证管理器 引用认证管理类和写死用户名和密码两中方式 -->
<authentication-provider
user-service-ref="userService">
<!-- 写死用户名和密码<user-service> <user name="admin" password="{MD5}e10adc3949ba59abbe56e057f20f883e"
authorities="ROLE_USER" /> </user-service> -->
<!-- 密码解密方式 -->
<password-encoder ref="passwordEncoder"></password-encoder>
</authentication-provider>
</authentication-manager>
<beans:bean id="userService"
class="security.demo.service.UserService"></beans:bean>
<beans:bean id="passwordEncoder"
class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"> </beans:bean>
</beans:beans>
5、创建security.demo.pojo包和User类
package security.demo.pojo;
public class User {
String username;
String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
6、创建security.demo.service包和UserService类
package security.demo.service;
import java.util.ArrayList;
import java.util.List;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
public class UserService implements UserDetailsService {
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
System.out.println("loadUserByUsername...");
// 定义权限类别ROLE_USER
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
// 从数据库获取用户名和密码
security.demo.pojo.User user = findUserByUsername(username);
//查到的数据不为空,将密码和认证角色列表返回,否则返回null
if (user != null) {
System.err.println("admin");
return new User(username, user.getPassword(), authorities);
} else {
System.err.println("null");
return null;
}
}
/*
* 模拟从数据库获取数据
*/
private security.demo.pojo.User findUserByUsername(String username) {
security.demo.pojo.User user = new security.demo.pojo.User();
user.setUsername("admin");
// 密码是123456经过加密后的字符串
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
String ps = encoder.encode("123456");
user.setPassword(ps);
return user;
}
}
7、在webapps目录下创建index.html文件
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>welcome to security home</title>
</head>
<body>welcome to security home!
</body>
</html>
8、在webapps目录下创建login.html文件,注意,方法必须post
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>security login</title>
</head>
<body>
<form action="/login" method="post">
Username: <input type="text" name="username" value="admin"><br />
Password: <input type="password" name="password" value="123456"> <br /> <input
type="submit" value="登录" />
</form>
</body>
</html>
9、将favicon.ico文件拷贝到根目录
10、目录结构
11、运行项目,访问localhost:9090
三、注意事项
1、使用配置文件方式配置用户名和密码时,在配置密码时需要加上{加密方式},否则报错(5.0.8版本)
<user-service>
<user name="admin" password="{MD5}e10adc3949ba59abbe56e057f20f883e" authorities="ROLE_USER" />
</user-service>
加密方式在core包下的org.springframework.security.crypto.factory.PasswordEncoderFactories类中
public static PasswordEncoder createDelegatingPasswordEncoder() {
String encodingId = "bcrypt";
Map<String, PasswordEncoder> encoders = new HashMap<>();
encoders.put(encodingId, new BCryptPasswordEncoder());
encoders.put("ldap", new LdapShaPasswordEncoder());
encoders.put("MD4", new Md4PasswordEncoder());
encoders.put("MD5", new MessageDigestPasswordEncoder("MD5"));
encoders.put("noop", NoOpPasswordEncoder.getInstance());
encoders.put("pbkdf2", new Pbkdf2PasswordEncoder());
encoders.put("scrypt", new SCryptPasswordEncoder());
encoders.put("SHA-1", new MessageDigestPasswordEncoder("SHA-1"));
encoders.put("SHA-256", new MessageDigestPasswordEncoder("SHA-256"));
encoders.put("sha256", new StandardPasswordEncoder());
return new DelegatingPasswordEncoder(encodingId, encoders);
}
2、必须有favicon.ico图标,否则报错
3、登录提交的方法必须是post,否则会重新跳到登录页,不报错
4、需要关掉csrf,<csrf disabled="true" />
5、必须给登录页放行,不进行验证,否则无法进入登录页,提示重定向过多
《完》