一、介绍
Spring 是非常流行和成功的 Java 应用开发框架,Spring Security 正是 Spring 家族中的成员。Spring Security 基于 Spring 框架,提供了一套 Web 应用安全性的完整解决方案。
SpringSecurity的核心功能:
用户认证(Authentication):系统判断用户是否能登录
用户授权(Authorization):系统判断用户是否有权限去做某些事情
SpringSecurity 特点:
Spring 技术栈的组成部分,与Spring 无缝整合。
全面的权限控制,能提供完整可扩展的认证和授权支持保护
专门为 Web 开发而设计。
重量级,需要引入各种家族组件与依赖
二、创建一个springboot项目
添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
运行
看控制台
去浏览器输入地址
验证成功后是这样的,出先404不要担心
权限概念
名称 | 英文名称 | 概念 |
主体 | principal | 使用系统的用户或设备或从其他系统远程登录的用户等等 |
认证 | authentication | 权限管理系统(通过登录操作)确认一个主体的身份,允许主体进入系统。简单说就是“主体”证明自己是谁。 |
授权 | authorization | 给用户分配权限:将操作系统的“权力”“授予”“主体”,这样主体就具备了操作系统中特定功能的能力。 |
提交用户名和密码后,将对用户名和密码进行身份验证。 扩展了 AbstractAuthenticationProcessingFilter,因此下图应该看起来非常相似:
该图基于我们的 SecurityFilterChain 图。
- 当用户提交其用户名和密码时,通过从实例中提取用户名和密码来创建一种身份验证类型。UsernamePasswordAuthenticationFilter
UsernamePasswordAuthenticationToken HttpServletRequest
- 接下来,将 传递到要进行身份验证的实例中。 外观的详细信息取决于用户信息的存储方式。UsernamePasswordAuthenticationToken AuthenticationManagerAuthenticationManager
- 如果身份验证失败,则失败。
SecurityContextHolder 被清除。
RememberMeServices.loginFail被调用。 如果未配置“记住我”,则这是无操作。 请参阅 Javadoc 中的 RememberMeServices 接口。
AuthenticationFailureHandler被调用。 请参阅 Javadoc 中的 AuthenticationFailureHandler 类
- 如果身份验证成功,则成功。
SessionAuthenticationStrategy收到新登录的通知。 请参阅 Javadoc 中的 SessionAuthenticationStrategy 接口。
身份验证在 SecurityContextHolder 上设置。 请参阅 Javadoc 中的 SecurityContextPersistenceFilter 类。
RememberMeServices.loginSuccess被调用。 如果未配置“记住我”,则这是无操作。 请参阅 Javadoc 中的 RememberMeServices 接口。
ApplicationEventPublisher发布 .InteractiveAuthenticationSuccessEvent
被调用。通常,这是一个 ,当我们重定向到登录页面时,它会重定向到 ExceptionTranslationFilter 保存的请求。AuthenticationSuccessHandlerSimpleUrlAuthenticationSuccessHandler
UsernamePasswordAuthenticationFilter : 对/login 的 POST 请求做拦截,校验表单中用户名,密码。
发出post
name=username
name=password
三、自定义用户名密码
方式一 : 通过配置文件设置
在application.properties文件中配置用户名和密码
spring.security.user.name=admin
spring.security.user.password=admin
方式二 :通过配置类进行配置
package com.aaa.config;
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.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import java.util.ArrayList;
import java.util.List;
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//创建 BCryptPasswordEncoder 的新实例
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
//使用编码器对密码进行编码
String password = bCryptPasswordEncoder.encode("123456");
//配置身份验证管理器
//用户1
auth.inMemoryAuthentication()
//设置密码编码器
.passwordEncoder(bCryptPasswordEncoder)
//创建新用户
.withUser("admin")
//Set the password
.password(password);
}
}
四、自定义页面与权限控制
自定义登陆页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/login" method="post">
用户名:<input type="text" name="username">
<br/>
密 码:<input type="password" name="userpassword">
<br/>
<input type="submit" value="login">
</form>
</body>
</html>
修改配置类
package com.aaa.config;
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.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import java.util.ArrayList;
import java.util.List;
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
/*------------------------------------------------------------------------*/
//资源
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
//添加资源
authorities.add(new SimpleGrantedAuthority("resource"));
authorities.add(new SimpleGrantedAuthority("ROLE_CE"));
/*------------------------------------------------------------------------*/
//创建 BCryptPasswordEncoder 的新实例
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
//使用编码器对密码进行编码
String password = bCryptPasswordEncoder.encode("123456");
/*------------------------------------------------------------------------*/
/*------------------------------------------------------------------------*/
//配置身份验证管理器
//用户1
auth.inMemoryAuthentication()
//设置密码编码器
.passwordEncoder(bCryptPasswordEncoder)
//创建新用户
.withUser("admin")
//设置密码
.password(password)
//设置资源
.roles("user");
/*------------------------------------------------------------------------*/
//用户2
auth.inMemoryAuthentication()
//设置密码编码器
.passwordEncoder(bCryptPasswordEncoder)
//创建新用户
.withUser("root")
//设置密码
.password(password)
//设置权限
.roles("role")
//设置资源
.authorities(authorities);
/*------------------------------------------------------------------------*/
}
@Override
protected void configure(HttpSecurity http) throws Exception {
/*------------------------------------------------------------------------*/
// 开始 配置自定义的信息
http.formLogin().loginPage("/login.html")//路径前面必须加 /
.loginProcessingUrl("/login")//跟提交的路径一样
.usernameParameter("username")//登陆账号
.passwordParameter("userpassword")//登陆密码
.defaultSuccessUrl("/test");//登陆成功的跳转路径
/*------------------------------------------------------------------------*/
/*------------------------------------------------------------------------*/
http.authorizeRequests().antMatchers("/login.html", "login").permitAll();//不用验证
http.authorizeRequests().antMatchers("/test").hasRole("test");//必须有哪个权限才能访问
http.authorizeRequests().antMatchers("/test").hasAnyAuthority("resource");//必须有哪个资源才能访问
//其他路径进行验证
http.authorizeRequests().anyRequest().authenticated();
//关闭csrf保护
http.csrf().disable();
/*------------------------------------------------------------------------*/
}
}
相关方法: 角色和权限都可以设置多个,以逗号分开
方法名称 | 说明 |
hasAuthority | 如果当前的主体具有指定的权限,则可以访问 |
hasAnyAuthority | 如果当前的主体有任何提供的角色的话,就可以访问 |
hasRole | 如果用户具备给定角色就允许访问 |
hasAnyRole | 用户具备任何一个角色都可以访问 |
当User对象没有对应权限时会返回403错误
五、注解的使用
使用注解前需要在启动器或配置类上添加注解:
@EnableGlobalMethodSecurity(securedEnabled=true,prePostEnabled = true,jsr250Enabled=true)
@Secured:判断是否具有角色:
注意:使用这个这个注解的时候对应的角色信息必须是以ROLE_**的形式出现,否则无法识别
controller
@Secured({"ROLE_CE"})
@GetMapping
public String test(){
return "Hello World!";
}
注意配置文件中,必须添加ROLE_
@RolesAllowed:判断是否具有角色:
注意:此注解不需要特别添加前缀ROLE_
controller
@RolesAllowed({"CE"})
@GetMapping
public String test(){
return "Hello World!";
}
@PreAuthorize:进入方法前进行权限验证:
注意:此注解不需要特别添加前缀ROLE_
controller
@PreAuthorize("hasRole('user')")
@GetMapping
public String test(){
return "Hello World!";
}
六、自定义实现类完成用户登录
自定义一个service
package com.aaa.servie;
import com.aaa.entiy.User;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
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;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class TestService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
String encode = bCryptPasswordEncoder.encode("111");
User user = new User("root",encode);
if (username.equals(user.getUserName())){
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority("ROLE_CE"));
return new org.springframework.security.core.userdetails.User(username,encode,authorities);
}
return null;
}
}
SecurityConfig类的配置
package com.aaa.config;
import org.springframework.context.annotation.Bean;
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.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Resource
protected UserDetailsService userDetailsService;
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
/*------------------------------------------------------------------------*/
// 开始 配置自定义的信息
http.formLogin().loginPage("/login.html")//路径前面必须加 /
.loginProcessingUrl("/login")//跟提交的路径一样
.usernameParameter("username")//登陆账号
.passwordParameter("userpassword")//登陆密码
.defaultSuccessUrl("/test");//登陆成功的跳转路径
/*------------------------------------------------------------------------*/
/*------------------------------------------------------------------------*/
http.authorizeRequests().antMatchers("/login.html", "login").permitAll();//不用验证
http.authorizeRequests().antMatchers("/test").hasRole("test");//必须有哪个权限才能访问
http.authorizeRequests().antMatchers("/test").hasAnyAuthority("resource");//必须有哪个资源才能访问
//其他路径进行验证
http.authorizeRequests().anyRequest().authenticated();
//关闭csrf保护
http.csrf().disable();
/*------------------------------------------------------------------------*/
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
}