1.基本原理
SpringSecurity 最核心的部分是由一系列的过滤器组成的过滤器链,每个过滤器都负责处理一种认证方式,请求经过任何一个过滤器过滤后,都会在请求上做一个标记,来记录认证是否成功,最后由FilterSecurityInterceptor根据我们配置的权限来决定是否能通过认证,从而访问我们的服务。今天我们主要使用的是用来处理表单登录的UsernamePasswordAuthenticationFilter。
2.实现:
代码结构:
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <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>com.springsecurity.login</groupId> <artifactId>security-login</artifactId> <version>1.0-SNAPSHOT</version> <dependencyManagement><!--用来管理依赖版本--> <dependencies> <dependency> <groupId>io.spring.platform</groupId> <artifactId>platform-bom</artifactId> <version>Brussels-SR4</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Dalston.SR2</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-core</artifactId> </dependency> <dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session</artifactId> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-taglibs</artifactId> </dependency> </dependencies> </project>
loginPage.html:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>security login</title> </head> <body> <h3>登录</h3> <form action="/authentication/form" method="post"> <table> <tr> <td>用户名:</td> <td><input type="text" name="username"></td> </tr> <tr> <td>密码:</td> <td><input type="password" name="password"></td> </tr> <tr> <td colspan="2"><button type="submit">登录</button></td> </tr> </table> </form> </body> </html>
SecurityConfig:
package com.security.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; /** * @author ShotMoon */ @Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Bean public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } /** * @description : * @param : [http] * @return : void */ @Override protected void configure(HttpSecurity http) throws Exception { http.formLogin() .loginPage("/loginPage.html")//指定自定义登录页面,不指定则使用默认配置的 .loginProcessingUrl("/authentication/form")//登录请求url-form表单的action .and() .authorizeRequests()/配置请求需要认证 .antMatchers( "/loginPage.html" ).permitAll()//指定不需认证的路径,防止出现登录页需要认证而发生死循环的状况 .anyRequest()//所有请求都需认证 .authenticated() .and() .csrf().disable(); } }
UserController:
package com.security.controller; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.GetMapping; /** * @author ShotMoon */ @RestController public class UserController { /** * @description : * @param : [] * @return : java.util.List<com.shotmoon.dto.User> * @date : 2018/5/10 18:28 */ @GetMapping("/user") public String enter(){ String success = "登录成功"; return success; } }
MyUserDetailService:
package com.security; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.authority.AuthorityUtils; 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.password.PasswordEncoder; import org.springframework.stereotype.Component; /** * @author ShotMoon */ @Component public class MyUserDetailService implements UserDetailsService{ private Logger logger = LoggerFactory.getLogger(getClass()); @Autowired private PasswordEncoder passwordEncoder; /** * @description : * @param : [username] * @return : org.springframework.security.core.userdetails.UserDetails * @date : 2018/5/12 23:11 */ public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { logger.info("用户名:" + username); //根据用户名到数据库查找用户的信息,这里我使用mock数据,大家可以根据自己的数据库来 String password = passwordEncoder.encode("123"); logger.info("数据库加密密码:" + password); return new User(username, password, true,true,true,true, //boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked可根据业务进行配置 AuthorityUtils.commaSeparatedStringToAuthorityList("admin")); } }
其中PassWordEncoder用来处理用户的加密及匹配,看一下源码:
这样,基于SpringSecurity实现加密的表单登录就完成了。package org.springframework.security.crypto.password; public interface PasswordEncoder { String encode(CharSequence var1);//加密输入的密码 boolean matches(CharSequence var1, String var2);//验证加密的密码与数据库数据是否匹配 }