springSecurity 配置代码
package com.example.springsecurity.config;
import com.fasterxml.jackson.databind.ObjectMapper;
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.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.GrantedAuthority;
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.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.session.SessionInformationExpiredEvent;
import org.springframework.security.web.session.SessionInformationExpiredStrategy;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.List;
/*
extends WebSecurityConfigurerAdapter
1.初始化配置用户以及权限 public void globalUserDetails(AuthenticationManagerBuilder auth)
2.设置Web权限 protected void configure(HttpSecurity http)
3.开放静态资源不需要权限即可访问 public void configure(WebSecurity web)
UserDetailsService
1.验证用户登录处理的方法 public UserDetails loadUserByUsername(String username)
SessionInformationExpiredStrategy
1.session过期回调的方法 public void onExpiredSessionDetected(SessionInformationExpiredEvent event)
UserDetailsService 和 globalUserDetails 方法个人理解区别
UserDetailsService 类似动态获取
globalUserDetails 类似初始化注入
*/
@Configuration
public class MyWebSecurityConfig extends WebSecurityConfigurerAdapter implements UserDetailsService, SessionInformationExpiredStrategy {
//JSON处理类
@Resource
ObjectMapper objectMapper;
//自定义的登录处理类
@Resource
MySuccessHandler mySuccessHandler;
//加密类
@Resource
BCryptPasswordEncoder BCrypt;
@Bean
public BCryptPasswordEncoder getBCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
/*//初始化创建一个用户并且赋予权限
@Autowired
public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
//设置用户
.passwordEncoder(BCrypt).withUser("user")
//设置密码
.password(BCrypt.encode("123"))
//该用户拥有的权限
.roles("Role_user")
.and().passwordEncoder(BCrypt).withUser("admin")
.password(BCrypt.encode("123"))
.roles("Role_admin")
.and().passwordEncoder(BCrypt).withUser("ying")
.password(BCrypt.encode("123"))
.roles("Role_all");
}*/
//设置Web权限
@Override
protected void configure(HttpSecurity http) throws Exception {
//关闭跨站请求伪造的防护
http.csrf().disable();
/*
1.使用formLogin模式登录 formLogin()
2.设置跳转自己的登录页面 .loginPage("/login.html")
3.登录认证在那个请求下进行处理 .loginProcessingUrl("/login")
4.登录成功后默认跳转到那个页面 .defaultSuccessUrl("index.html")
5.设置自定义登录处理类 .successHandler(mySuccessHandler);
注:.loginPage("/login.html") 和 .successHandler(mySuccessHandler); 是互斥的调整页面和处理类只能选着其中一种
*/
http.formLogin()
.loginPage("/login.html")
.loginProcessingUrl("/user/login")
.defaultSuccessUrl("/index.html").permitAll();
// .successHandler(mySuccessHandler);
/*
1.忽略哪些请求不需要拦截也可访问 .antMatchers("/", "/index").permitAll()
2.设置哪些请求可以被哪些角色权限进行访问 .antMatchers("/select").hasAnyRole("Role_user", "Role_admin")
注:.antMatchers("/update", "/delete") 可以写多个
hasAnyRole("Role_user", "Role_admin") 可以写多个 推荐直接用这个
hasRole("Role_user") 只能写一个
*/
http.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/select").hasAnyRole("Role_user", "Role_admin")
.antMatchers("/insert", "/update", "/delete").hasAnyRole("Role_admin")
.anyRequest().authenticated();
//自定义权限不够访问出错时展示给用户的有好页面
//resources/static/error.html
http.exceptionHandling().accessDeniedPage("/error.html");
//设置用户退出登录的路径/logout,退出登录后访问的路径/index
http.logout().logoutUrl("/logout").logoutSuccessUrl("/login");
/*
1.session管理器 .sessionManagement()
2.session的生成策略,默认IF_REQUIRED,无状态应用STATELESS .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
3.session过期后跳转的页面 .invalidSessionUrl("/login.html")
4.
.migrateSession() 迁移session重新把session复制一份,重新生成一个sessionID
.changeSessionId() 不会复制session,重新贴一个sessionID
.newSession() 直接创建一个新的session
.none() 原来的session不会做任何失效,永不过期
5.允许最大的Session数量 .maximumSessions(1)
6.
.maxSessionsPreventsLogin(false)
true 不允许在登录
false 运行登录,但会顶掉之前的登录
7. session超时后进行的回调类 .expiredSessionStrategy()
*/
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.invalidSessionUrl("/login.html")
.sessionFixation().migrateSession()
.maximumSessions(1)
.maxSessionsPreventsLogin(false)
.expiredSessionStrategy(this);
// 开启记住我功能
http.rememberMe().rememberMeParameter("remeber");
}
//开放静态资源不需要权限即可访问
@Override
public void configure(WebSecurity web) {
//开放静态资源不需要权限即可访问
web.ignoring().antMatchers("/css/**", "/fonts/**", "img/**", "/js/**");
}
//验证用户登录处理的方法
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
/*
User类来自import org.springframework.security.core.userdetails.User;
public User(@NotNull String username, //用户输入的用户名
@NotNull String password, //查询数据库获取用户密码,需要用过BCrypt.encode("123") 进行加密
//查询数据库获获取用户的权限角色集合
@NotNull java.util.Collection<? extends org.springframework.security.core.GrantedAuthority> authorities)
*/
System.out.println("当前用户username=" + username);
//设置用户有哪些角色权限
List<GrantedAuthority> auths = AuthorityUtils.commaSeparatedStringToAuthorityList("Role_user");
return new User(username, BCrypt.encode("123"), auths);
}
//session过期回调的方法
@Override
public void onExpiredSessionDetected(SessionInformationExpiredEvent event) throws IOException {
System.out.println("session已过期!!!!!!!");
event.getResponse().setContentType("application/json;charset=UTF-8");
event.getResponse().getWriter().write(objectMapper.writeValueAsString("{mes:'session失效后的回调方法=--------',code:200}"));
}
}
自定义登录处理类
package com.example.springsecurity.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
//自定义的登录处理类
@Component
public class MySuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
@Value("${ying.loginType}")
private String loginType;
private static final ObjectMapper objectMapper = new ObjectMapper();
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws ServletException, IOException {
//判断是否返回JSON格式
if (loginType.equalsIgnoreCase("JSON")) {
response.setContentType("application/json;charset=UTF-8");
//返回前端JSON格式响应数据
response.getWriter().write(objectMapper.writeValueAsString("{mes:'success',code:200}"));
} else {
super.onAuthenticationSuccess(request, response, authentication);
}
}
}
测试Controller
package com.example.springsecurity.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class MyUserController {
/*
需要开启注解才能使用
@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true) //开启权限注解模式 prePostEnabled是否在访问方法前验证权限
@Secured({"Role_user","Role_admin"})
@PreAuthorize("hasAnyRole('Role_admin')")
*/
@GetMapping("/select")
// @Secured({"Role_user","Role_admin"})
// @PreAuthorize("hasAnyRole('Role_admin')")
public String select() {
System.out.println("select");
return "select";
}
@GetMapping("/insert")
public String insert() {
System.out.println("insert");
return "insert";
}
@GetMapping("/update")
public String update() {
System.out.println("update");
return "update";
}
@GetMapping("/delete")
public String delete() {
System.out.println("delete");
return "delete";
}
}
static 静态页面
路径放入/static路径下
error.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
当前用户权限不够!!
</body>
</html>
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
index主页面!!
<br>
<a href="/select">/select</a>
<br>
<a href="/update">/update</a>
<br>
<a href="/insert">/insert</a>
<br>
<a href="/update">/update</a>
<br>
<a href="/logout">/logout</a>
</body>
</html>
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/user/login" method="post">
<label>
用户名:<input type="text" name="username">
</label>
<br>
<label>
密码:<input type="text" name="password">
</label>
<br>
<input type="submit" value="login"/>
</form>
</body>
</html>
yaml配置文件
server:
port: 80
servlet:
session:
timeout: 300m
cookie:
http-only: true #如果为true,则浏览器脚本无法访问cookie
secure: false #如果为true,则仅通过HTTPS连接发送cookie,HTTP无法携带cookie
ying:
loginType: JSONNO
pom文件
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.8.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>springsecurity</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springsecurity</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>