1、简介
应用程序的安全性通常体现在两个方面:认证和授权。
认证是确认某主体在某系统中是否合法、可用的过程。这里的主体既可以是登录系统的用户,也 可以是接入的设备或者其他系统。
授权是指当主体通过认证之后,是否允许其执行某项操作的过程。 这些概念并非Spring Security独有,而是应用安全的基本关注点。Spring Security可以帮助我们更便 捷地完成认证和授权。
2、基本使用
1、依赖引入
<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.my.test.security</groupId>
<artifactId>SpringSecurityTest</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.RELEASE</version>
</parent>
<dependencies>
<!-- SpringBoot依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- SpringSecurity -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- jdbc -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- lombok依赖 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
</dependencies>
</project>
2、controller及启动类
@SpringBootApplication
@RestController
public class SecurityApp {
@GetMapping("/")
public String hello() {
return "Welcome to hello page";
}
public static void main(String[] args) {
SpringApplication.run(SecurityApp.class, args);
}
}
3、配置文件配置
server:
port: 8888
spring:
security:
user:
name: root
password: Admin123
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/my_test?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
username: root
password: 666666
4、测试
访问:localhost:8888时,会进行验证,输入配置好的用户名密码便可进入访问的controller
3、WebSecurityConfigurerAdapter实现路由及身份权限验证
1、依赖
同2中依赖
2、配置类-继承WebSecurityConfigurerAdapter并进行设置
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
/**
* session管理策略
* ALWAYS---总是创建HttpSession
IF_REQUIRED---Spring Security只会在需要时创建一个HttpSession
NEVER---Spring Security不会创建HttpSession,但如果它已经存在,将可以使用HttpSession
STATELESS---Spring Security永远不会创建HttpSession,它不会使用HttpSession来获取SecurityContext
*/
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER);
http.authorizeRequests()
/**
* 设置用户及角色认证,控制controller的访问权限
*/
.antMatchers("/user/**").hasRole("USER")
.antMatchers("/manager").hasRole("MANAGER")
//登出跳转
.antMatchers("/logoutSuccess").permitAll()
.antMatchers("/").permitAll()
.and()
.formLogin() //基于表单登录
.permitAll() //允许访问登录
/* 指定登录页 */
//.loginPage("/login")
/* 指定登录时访问的URL */
//.loginProcessingUrl("/security/login")
.and()
.logout()
/*退出时访问的url*/
.logoutUrl("/logout")
/**
* 注意logoutSuccessUrl不要与logoutSuccessHandler一起使用,否则logoutSuccessHandler将失效。
*/
/*退出成功后要做的操作(如记录日志),和logoutSuccessUrl互斥*/
//.logoutSuccessHandler(new CoreqiLogoutSuccessHandler())
/*退出成功后跳转的页面--需配置权限,否则会转向登录页*/
.logoutSuccessUrl("/logoutSuccess")
/*退出时要删除的Cookies的名字*/
//.deleteCookies("JSESSIONID")
.and()
//csrf是Spring Security提供的跨站请求伪造防护功能
.csrf().disable();
super.configure(http);
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
/**
* 普通用户权限设置
*/
auth.inMemoryAuthentication()
.passwordEncoder(new BCryptPasswordEncoder())
.withUser("user")
/*密码需进行编码存储,否则匹配时,会自动进行解码操作*/
.password(new BCryptPasswordEncoder().encode("user123")).roles("USER");
/**
* 管理员权限设置
*/
auth.inMemoryAuthentication()
.passwordEncoder(new BCryptPasswordEncoder()).withUser("manager")
.password(new BCryptPasswordEncoder().encode("manager123")).roles("MANAGER");
}
}
3、controller层代码
@SpringBootApplication
@RestController
public class SecurityApp {
@GetMapping("/")
public String hello() {
return "Welcome to hello page";
}
@GetMapping("/user")
public String userPage() {
return "user page";
}
@GetMapping("/manager")
public String managerPage() {
return "manager page";
}
@GetMapping("/logoutSuccess")
public String logoutPage() {
return "logout success!";
}
public static void main(String[] args) {
SpringApplication.run(SecurityApp.class, args);
}
}
4、使用SpringSecurity结合SpringDataJpa实现RBAC模式权限管理
1、使用登录成功/失败后置处理–Handler
成功Handler
@Component
public class LoginSuccessHandler implements AuthenticationSuccessHandler{
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
response.setContentType("application/json; charset=utf-8");
response.sendRedirect("/user");
}
}
失败Handler
@Component
public class LoginFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException {
System.out.println("登录失败!");
response.sendRedirect("/logoutFailure");
}
}
2、实体类继承UserDetails并实现authorities的list以及dao接口
实体类
@Entity
@Table(name = "security_user")
@Data
public class SecurityUser implements UserDetails{
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Integer id;
@Column(name = "username")
private String username;
@Column(name = "password")
private String password;
/*GrantedAuthority接口的默认实现SimpleGrantedAuthority*/
@ElementCollection(targetClass = GrantedAuthority.class)
private List<GrantedAuthority> authorities;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return this.authorities;
}
@Override
public boolean isAccountNonExpired() {
// TODO Auto-generated method stub
return true;
}
@Override
public boolean isAccountNonLocked() {
// TODO Auto-generated method stub
return true;
}
@Override
public boolean isCredentialsNonExpired() {
// TODO Auto-generated method stub
return true;
}
@Override
public boolean isEnabled() {
// TODO Auto-generated method stub
return true;
}
}
dao接口
public interface UserDao extends JpaRepository<SecurityUser, Integer>, JpaSpecificationExecutor<SecurityUser> {
@Query(value = "select * from security_user as u where u.username = ?1",nativeQuery = true)
SecurityUser getUserByUsername(String username);
}
3、实现UserDetailsService并配置user
@Service
public class UserDetailServiceImp implements UserDetailsService {
@Autowired
private UserDao userDao;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
SecurityUser user = userDao.getUserByUsername(username);
user.setUsername(username);
user.setPassword(encoder.encode(user.getPassword()));
//user.setPassword(user.getPassword());
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
GrantedAuthority authority = new SimpleGrantedAuthority("ROLE_USER");
authorities.add(authority);
user.setAuthorities(authorities);
return user;
}
}
4、WebSecurityConfig注入UserDetailsService实现类及其他配置
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private LoginSuccessHandler successHandler;
@Autowired
private LoginFailureHandler failureHandler;
@Autowired
private UserDetailsService userDetailServiceImp;
@Override
protected void configure(HttpSecurity http) throws Exception {
/**
* session管理策略 ALWAYS---总是创建HttpSession IF_REQUIRED---Spring
* Security只会在需要时创建一个HttpSession NEVER---Spring
* Security不会创建HttpSession,但如果它已经存在,将可以使用HttpSession STATELESS---Spring
* Security永远不会创建HttpSession,它不会使用HttpSession来获取SecurityContext
*/
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER);
http.authorizeRequests()
/**
* 设置用户及角色认证,控制controller的访问权限
*/
.antMatchers("/user/**").hasRole("USER")
.antMatchers("/manager").hasRole("MANAGER")
// 登出跳转
.antMatchers("/logoutSuccess").permitAll()
.antMatchers("/").permitAll().and().formLogin() // 基于表单登录
.permitAll() // 允许访问登录
.successHandler(successHandler).failureHandler(failureHandler)
/* 指定登录页 */
// .loginPage("/login")
/* 指定登录时访问的URL */
// .loginProcessingUrl("/security/login")
.and().logout()
/* 退出时访问的url */
.logoutUrl("/logout")
/**
* 注意logoutSuccessUrl不要与logoutSuccessHandler一起使用,否则logoutSuccessHandler将失效。
*/
/* 退出成功后要做的操作(如记录日志),和logoutSuccessUrl互斥 */
// .logoutSuccessHandler(new CoreqiLogoutSuccessHandler())
/* 退出成功后跳转的页面--需配置权限,否则会转向登录页 */
.logoutSuccessUrl("/logoutSuccess")
/* 退出时要删除的Cookies的名字 */
// .deleteCookies("JSESSIONID")
.and()
// csrf是Spring Security提供的跨站请求伪造防护功能
.csrf().disable();
super.configure(http);
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailServiceImp);
}
}