第一步,空Spring Boot环境。
暂时不添加了Spring Security依赖。
第二步,确保项目能够正常运行。
启动启动项 Application.java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@RestController
@EnableAutoConfiguration
public class AuthorityApplication {
public static void main(String[] args) {
SpringApplication.run(AuthorityApplication.class, args);
}
// localhost:8080/
@RequestMapping(value = "/")
public String home() {
return "这是根路径";
}
// localhost:8080/hello
@RequestMapping(value = "/hello")
public String hello() {
return "hello";
}
}
确保Spring Boot项目能够正常启动。
第三步,添加了Spring Security依赖。
org.springframework.bootspring-boot-starter-security
重启Application,访问 localhost:8080/ ,出现以下界面,自动跳转至 http://localhost:8080/login ,需要登录,实现了认证功能。
第四步,自定义Spring Security配置文件 SpringSecurityCustomConfig.java 。
1.实现对主路径放行、其他路径请求需要验证、注销操作允许任意权限访问、表单登录允许任意权限访问。
2.对js、css、images不做拦截。
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;@Configuration//配置文件@EnableWebSecurity//打开web支持
public class SpringSecurityCustomConfig extends WebSecurityConfigurerAdapter {@Override
protected void configure(HttpSecurity http) throws Exception {//决定那些请求被拦截
http.authorizeRequests()
.antMatchers("/").permitAll()//主路径放行
.anyRequest().authenticated()//其他请求需经过验证
.and()
.logout().permitAll()//注销操作允许任意权限访问
.and()
.formLogin().permitAll();//表单登录允许任意权限访问
http.csrf().disable();//关闭默认的csrf认证
}@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/js'/**", "/css/**", "/images/**");//对js、css、images不做拦截
}
}
访问主路径 http://localhost:8080/ ,不需要验证。
访问其他路径 http://localhost:8080/hello ,需要验证。出现以下界面,自动跳转至 http://localhost:8080/login
Spring Security常见案例
案例一:只需登录
不希望花太多时间做登录功能,也不希望数据库存储登录用户名和密码。
自定义Spring Security配置文件 SpringSecurityCustomConfig.java ,通知系统在内存中有一个用户名为“admin”,用户密码为“123456”的用户,该用户角色为“ADMIN”。
访问需要验证的路径 http://localhost:8080/hello ,分别输入错误信息和正确信息。
访问 http://localhost:8080/login?logout 即可登出。
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration// 配置文件
@EnableWebSecurity// 打开web支持
public class SpringSecurityCustomConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// Spring Security提供了一套基于内存的验证
auth.inMemoryAuthentication()
.withUser("admin")
.password("123456")
.roles("ADMIN");// 自定义角色
// 可以添加若干个auth.inMemoryAuthentication()
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// 决定那些请求被拦截
http
.authorizeRequests()
.antMatchers("/").permitAll()// 主路径放行
.anyRequest().authenticated()// 其他请求需经过验证
.and()
.formLogin().permitAll()// 表单登录允许任意权限访问
.and()
.logout().permitAll();// 注销操作允许任意权限访问
http.csrf().disable();// 关闭默认的csrf认证
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/js'/**", "/css/**", "/images/**");// 对js、css、images不做拦截
}
}
案例二:指定角色,权限按角色分配
自定义Spring Security配置文件 SpringSecurityCustomConfig.java ,通知系统在内存中有一个用户名为“caiji”,用户密码为“caiji”的用户,该用户角色为“USER”。
访问需要验证的路径 http://localhost:8080/hello
访问需要验证的路径 http://localhost:8080/roleAuth ,caiji无权限访问,admin可以访问
Application.java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@SpringBootApplication@RestController@EnableAutoConfiguration//Spring Boot会自动根据jar依赖自动配置项目@EnableGlobalMethodSecurity(prePostEnabled = true)// 启动注解@PreAuthorize的作用
public class AuthorityApplication {
public static void main(String[] args) {
SpringApplication.run(AuthorityApplication.class, args);
}// localhost:8080/
@RequestMapping(value = "/")
public String home() {return "这是根路径";
}// localhost:8080/hello@RequestMapping(value = "/hello")
public String hello() {return "hello ADMIN";
}// localhost:8080/hello@PreAuthorize("hasRole('ROLE_ADMIN')")//RoleVote中定义需要添加前缀@RequestMapping(value = "/roleAuth")
public String roleAuth() {return "hello USER";
}
}
SpringSecurityCustomConfig.jaca@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {//Spring Security提供了一套基于内存的验证
auth.inMemoryAuthentication()
.withUser("admin")
.password("123456")
.roles("ADMIN");//自定义角色//可以添加若干个auth.inMemoryAuthentication()
auth.inMemoryAuthentication().withUser("caiji").password("caiji").roles("USER");//USER用户
}
案例三:数据库管理用户
新增 UserService 类,实现 UserDetailsService 。
UserService.java
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
@Component
public class UserService implements UserDetailsService {@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {returnnull;
}
}
将用户admin、caiji放入数据库,使用UserService管理。
SpringSecurityCustomConfig.java@Autowired
private UserService userService;@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {//Spring Security提供了一套基于内存的验证//auth.inMemoryAuthentication()// .withUser("admin")// .password("123456")// .roles("ADMIN");//自定义角色// //可以添加若干个auth.inMemoryAuthentication()// auth.inMemoryAuthentication().withUser("caiji").password("caiji").roles("USER");//USER用户
auth.userDetailsService(userService);
}
自定义密码管理验证,新建 PasswordCustomEncoder 类,实现 PasswordEncoder 接口。
Spring Security提供了许多对密码加密的封装类,此处以MD5加密为例。
PasswordCustomEncoder.java
import org.springframework.security.authentication.encoding.Md5PasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;/**
* @author tabjin* create at 2019-06-29 09:05
* @program authority* @description*/public class PasswordCustomEncoder implements PasswordEncoder {
private final static String SALT= "123456";/**
*加密方法,对原始密码加密* @paramcharSequence* @return
*/
@Override
public String encode(CharSequence charSequence) {
Md5PasswordEncoder md5PasswordEncoder=new Md5PasswordEncoder();return md5PasswordEncoder.encodePassword(charSequence.toString(), SALT);//加密并附加123456
}/**
*匹配方法,对原始密码和加密后密码匹配* @paramcharSequence* @params* @return
*/
@Override
public boolean matches(CharSequence charSequence, String s) {
Md5PasswordEncoder md5PasswordEncoder=new Md5PasswordEncoder();return md5PasswordEncoder.isPasswordValid(s, charSequence.toString(), SALT);//保证盐值和加密时一样
}
}
回到定义认证的类 SpringSecurityCustomConfig.java
SpringSecurityCustomConfig.java@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {//自定义处理
auth.userDetailsService(userService).passwordEncoder(new PasswordCustomEncoder());//指定好UserService后添加自定义密码验证器//Spring Security 默认数据库处理,表结构位于users.ddl
auth.jdbcAuthentication().usersByUsernameQuery("").passwordEncoder(new PasswordCustomEncoder());
}