[官方文档]
https://spring.io/projects/spring-security
[官方API地址]
https://docs.spring.io/spring-security/site/docs/5.4.6/api/
概述:
Spring Security是一个提供身份验证、授权和防范常见攻击的框架。由于对命令式应用程序和响应式应用程序都提供了一流的支持,它是保护基于spring的应用程序的实际上的标准。
[核心功能] 主要功能就是身份的认证及授权
SpringBoot+spring-security+jwt实现认证授权实现认证及授权
POM依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</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>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.auth0/java-jwt -->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.15.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
</dependencies>
配置spring-security
package com.yingdongshuju.springsecutity.config;
import com.yingdongshuju.springsecutity.filter.LoginFilter;
import com.yingdongshuju.springsecutity.filter.TokenFilter;
import com.yingdongshuju.springsecutity.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
/**
* @Author: dawang
* @Date: 2021/4/13 17:51
*/
@Configuration
@EnableWebSecurity
//开启spring-securty注解功能
@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled=true,jsr250Enabled=true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserService userService;
/**
* 此方法采用的是链式编程,使用and()方法进行参数的拼接
**/
@Override
protected void configure(HttpSecurity http) throws Exception {
//允许使用RequestMatcher实现(即通过URL模式)基于HttpServletRequest限制访问
http
.csrf().disable() //关闭csrf功能
//配置接口路径的权限
// .authorizeRequests()
// .antMatchers("/vip/**").hasAnyRole("ADMIN")
// .antMatchers("/").permitAll()
// .antMatchers("/success").permitAll()
// .and()
//配置表单登陆
// .formLogin()
// .loginProcessingUrl("/doLogin")
// .loginPage("/login")
// .permitAll()
// .and()
//这里使用的是过滤器实现登陆认证授权
.addFilter(new LoginFilter(this.authenticationManager()))
.addFilter(new TokenFilter(this.authenticationManager()))
.sessionManagement().disable()
;
}
//密码加密类
@Bean
public PasswordEncoder getPasswordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//来自内存
/* auth.inMemoryAuthentication()
.passwordEncoder(new BCryptPasswordEncoder())
.withUser("user").password(new BCryptPasswordEncoder().encode("123456")).roles("USER")
.and()
.withUser("admin").password(new BCryptPasswordEncoder().encode("123456")).roles("ADMIN", "USER");*/
//来自数据库
auth.userDetailsService(userService).passwordEncoder(getPasswordEncoder());
}
}
[什么是csrf]
https://baike.baidu.com/item/%E8%B7%A8%E7%AB%99%E8%AF%B7%E6%B1%82%E4%BC%AA%E9%80%A0/13777878?fromtitle=CSRF&fromid=2735433&fr=aladdin
授权
/**
* token过滤器 验证token有效性
*
* @author smalljop
*/
@Component
@Slf4j
@RequiredArgsConstructor
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
private final TokenService tokenService;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
//log.info("REQUEST_PATH: {}",request.getServletPath());
//System.err.println("REQUEST_PATH:"+request.getServletPath());
LoginUserEntity loginUser = tokenService.getLoginUser(request);
if (ObjectUtil.isNotNull(loginUser) && ObjectUtil.isNull(SecurityUtils.getAuthentication())) {
tokenService.verifyToken(loginUser);
//创建授权对象
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
//存入授权内容
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
chain.doFilter(request, response);
}
}
spring-secutity注解
@EnableGlobalMethodSecurity
在方法上增加Spring Security注解,主要是为了判断当前用户是否有资格执行该方法,如是否拥有某权限、是否为当前登录用户。 spring security默认禁用注解,要想开启注解,需要在继承
WebSecurityConfigurerAdapter的类上加@
EnableGlobalMethodSecurity注解,并在该类中将AuthenticationManager定义为bean。 提供了三种注解。
JSR-250注解
@DenyAll:拒绝所有访问。
@RolesAllowed({“USER”,”ADMIN”}):该方法只要具有USER、ADMIN任意一种权限即可访问。这里省略前缀ROLE_,实际权限可能是ROLE_ADMIN。
@PermitAll:允许所有访问。
prePostEnable注解
开启此注解方法:
@EnableGlobalMethodSecurity(prePostEnabled = true)
@PreAuthorize:在方法执行前判断,可以调用方法参数,主要利用Java8的参数名反射特性,如果没用Java8也可以使用spring security的@P标注参数,或者Spring Data的@Param标注参数。
//通过表达式判断用户是否为当前登录用户或拥有ROLE_ADMIN权限
@PreAuthorize("#userId == authentication.principal.userId or hasAuthority(‘ADMIN’)")
public void changePassword(@P("userId") long userId ){}

写权限校验
@GetMapping("/write")
@RolesAllowed("ROLE_ADMIN")
@PreAuthorize("hasAuthority('write')")
@ResponseBody
public String test01(){
return "你可以写了";
}
@PostAuthorize:在方法执行后判断,可以调用参数。如果EL为false,虽然方法已经执行完了也可能会回滚,EL变量returnObject表明返回的对象。
@PostAuthorize
User getUser("returnObject.userId == authentication.principal.userId
or hasPermission(returnObject, 'ADMIN')");
@PreFilter:在方法执行前判断,可以调用方法参数,对参数值进行过滤、处理或修改。EL变量filterObject表明参数,如有多个参数则用filterTarget注解参数,那么参数必须是集合或数组才行(很少用到,与分页技术不兼容)。 securedEnable注解 @Secured:是否有权限访问
@Secured("IS_AUTHENTICATED_ANONYMOUSLY") public Account readAccount(Long id);
@Secured("ROLE_TELLER")
配置swagger过滤
import com.yingdongshuju.filter.HeardFilter;
import com.yingdongshuju.filter.LoginFilter;
import com.yingdongshuju.filter.TokenFilter;
import com.yingdongshuju.service.UserService;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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;
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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true, jsr250Enabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserService userService;
@Autowired
private AccessDeniedHandlerConfig accessDeniedHandlerConfig;
@Autowired
private AuthenticationEntryPointConfig authenticationEntryPointConfig;
@Override
protected void configure(HttpSecurity http) throws Exception {
//允许使用RequestMatcher实现(即通过URL模式)基于HttpServletRequest限制访问
http
.cors()//开启跨域支持
.and()
.authorizeRequests().antMatchers(HttpMethod.OPTIONS).permitAll()
.and()
.csrf().disable()//关闭csrf
.logout().disable()
.addFilter(new LoginFilter(this.authenticationManager()))//加入登陆过滤器
.addFilter(new TokenFilter(this.authenticationManager()))//加入token过滤器
.sessionManagement().disable()//禁用session
;
}
@Bean
public PasswordEncoder getPasswordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//来自内存
/* auth.inMemoryAuthentication()
.passwordEncoder(new BCryptPasswordEncoder())
.withUser("user").password(new BCryptPasswordEncoder().encode("123456")).roles("USER")
.and()
.withUser("admin").password(new BCryptPasswordEncoder().encode("123456")).roles("ADMIN", "USER");*/
//来自数据库
auth.userDetailsService(userService).passwordEncoder(getPasswordEncoder());
}
/**
* 配置静态资源放行
*
* @param web
* @throws Exception
*/
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers("/v2/api-docs", "/swagger-resources/configuration/ui",
"/swagger-resources", "/swagger-resources/configuration/security",
"/swagger-ui.html", "/css/**", "/js/**", "/images/**", "/webjars/**", "**/favicon.ico", "/index"
);
}
}
协助:
协助文档地址:
https://docs.spring.io/spring-security/site/docs/current/reference/html5/
官方demo地址:
https://docs.spring.io/spring-security/site/docs/current/reference/html5/#samples


