一、Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。

  二、security和springboot也做了深度的契合,所以我们这里使用security来配置相关访问。因为项目可以做前后端的分理,我这里就不讲对于后台处理页面的配置了。这里主要是讲一些针对于纯后端开发,进行security的相关配置,当然只是其中一部分。

  三、讲到的点主要有:跨域、认证、加密、权限控制等。

  四、实现部分

  1、pom.xml需要的依赖(这里只写主要部分,parent等自己按需要导入依赖)

     <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

  说明:说明一点,我这里使用的是2.0.0的版本,如何有需要可以自己根据不同的版本进行配置

  2、主要的配置部分

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
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.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.csrf.CsrfFilter;
import org.springframework.web.filter.CorsFilter; @Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter { //跨域
@Autowired
private CorsFilter corsFilter; //认证处理类
@Autowired
private DaoAuthenticationProvider daoAuthenticationProvider; //认证成功
@Autowired
private AuthenticationSuccessHandler successHandler; //认证失败
@Autowired
private AuthenticationFailureHandler failureHandler; //登出成功
@Autowired
private LogoutSuccessHandler logoutSuccessHandler; @Autowired
private AccessDeniedHandler deniedHandler; //认证EntryPoint
@Autowired
private AuthenticationEntryPoint entryPoint; @Override
protected void configure(AuthenticationManagerBuilder builder) throws Exception {
builder.authenticationProvider(daoAuthenticationProvider);
} @Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers(HttpMethod.OPTIONS, "/api/**")
.antMatchers("/swagger-ui.html")
.antMatchers("/webjars/**")
.antMatchers("/swagger-resources/**")
.antMatchers("/v2/**");
} @Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.addFilterBefore(corsFilter, CsrfFilter.class)
.exceptionHandling()
.authenticationEntryPoint(entryPoint)
.accessDeniedHandler(deniedHandler)
.and()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin().loginPage("/api/user/login")
.successHandler(successHandler)
.failureHandler(failureHandler)
.and()
.logout().logoutUrl("/api/user/logout")
.logoutSuccessHandler(logoutSuccessHandler)
.and()
.headers()
.frameOptions()
.disable()
.and()
.sessionManagement().maximumSessions(1800);
}
}

  3、csrf防护

  这个我这里不详细讲,主要的目的就是每次访问的时候除了带上自己的访问凭据以外,还需要带上每次csrf的票据。当然这个是会根据具体的会话进行变化的,也就是防止csrf攻击。

  如果csrf放开配置方式可以为cookie

  即:将.csrf().disable()换成.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())

  如果存在后端接口忽略的加入:.ignoringAntMatchers("/api/user/login")

  访问的时候带上csrf的访问票据,携带方式为下面2种方式。票据的获取方式为第一次访问的时候回通过cookie的方式带入

  request:_csrf:票据

  header:X-XSRF-TOKEN:票据

  4、跨域(配置方式见注入部分)

  跨域问题我相信在使用前后台分理的时候肯定会出现这种问题,那么怎么样配置跨域问题呢!这里提供了一种方式(CorsFilter.class)

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter; import java.util.ArrayList;
import java.util.List; @Configuration
public class CorsFilterConfiguration { @Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration corsConfiguration = new CorsConfiguration();
List<String> allowedOrigins = new ArrayList<>();
allowedOrigins.add("*");
List<String> allowedMethods = new ArrayList<>();
allowedMethods.add("*");
List<String> allowedHeaders = new ArrayList<>();
allowedHeaders.add("*");
List<String> exposedHeaders = new ArrayList<>();
exposedHeaders.add("Link");
exposedHeaders.add("X-Total-Count");
corsConfiguration.setAllowedOrigins(allowedOrigins);
corsConfiguration.setAllowedMethods(allowedMethods);
corsConfiguration.setAllowedHeaders(allowedHeaders);
corsConfiguration.setExposedHeaders(exposedHeaders);
corsConfiguration.setAllowCredentials(true);
corsConfiguration.setMaxAge(1800L);
source.registerCorsConfiguration("/api/**", corsConfiguration);return new CorsFilter(source);
}
}

  5、认证处理以及加密处理

  这里的加密方式采用的是springsecurity提供的一种加密方式:BCryptPasswordEncoder(hash、同一密码加密不一样的密钥),认证配置见builder部分

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; @Configuration
public class PasswordEncoderConfiguration { /**
* 密码加密
*/
@Bean
public BCryptPasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
}
import com.cetc.domain.Role;
import com.cetc.domain.User;
import com.cetc.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
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.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList;
import java.util.List; @Service
@Transactional
public class AuthDetailsService implements UserDetailsService { @Autowired
private UserRepository userRepository; @Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username);
if (user == null){
throw new UsernameNotFoundException("用户不存在!");
}
List<SimpleGrantedAuthority> simpleGrantedAuthorities = new ArrayList<>();
List<Role> roles = user.getRoles();
if (roles != null && !roles.isEmpty()) {
roles.stream().forEach(role -> simpleGrantedAuthorities.add(new SimpleGrantedAuthority(role.getRoleType())));
}
return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), simpleGrantedAuthorities);
}
}

  说明:这里的UsernameNotFoundException如果是默认配置,是不能被处理类所捕获的。原因:DaoAuthenticationProvider父类AbstractUserDetailsAuthenticationProviderhideUserNotFoundExceptionstrue

  解决方式重新配置:DaoAuthenticationProvider 

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; @Configuration
public class CustomDaoAuthenticationProvider { @Autowired
private AuthDetailsService authDetailsService; @Autowired
private BCryptPasswordEncoder passwordEncoder; @Bean
public DaoAuthenticationProvider daoAuthenticationProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(authDetailsService);
provider.setPasswordEncoder(passwordEncoder);
provider.setHideUserNotFoundExceptions(false);
return provider;
}
}

  然后修改builder.userDetailsService(authDetailsService).passwordEncoder(passwordEncoder);builder.authenticationProvider(provider);

  这种方式就可以解决异常包装的问题了,这里我们是采用的原生的配置方式。

  6、各个切入点(AuthenticationEntryPoint、AccessDeniedHandler、AuthenticationSuccessHandler、AuthenticationFailureHandler、LogoutSuccessHandler)五个切入点,作用就是在对应操作过后,可以根据具体的切入点进行相应异常的处理

import com.alibaba.fastjson.JSONObject;
import com.cetc.constant.SystemErrorCode;
import com.cetc.dto.MenuDTO;
import com.cetc.result.ResponseMsg;
import com.cetc.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; import java.util.List; @Configuration
public class CustomHandlerConfiguration { @Autowired
private IUserService userService; /**
* 访问接入点处理
* @return
*/
@Bean
public AuthenticationEntryPoint authenticationEntryPoint() {
AuthenticationEntryPoint entryPoint = (request, response, e) -> {
ResponseMsg<String> responseMsg = new ResponseMsg<>();
responseMsg.setStatus(false);
responseMsg.setBody(e.getMessage());
responseMsg.setErrorCode(SystemErrorCode.NO_LOGIN);
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
response.getWriter().write(JSONObject.toJSONString(responseMsg));
};
return entryPoint;
} /**
* 接入过后问题处理
* @return
*/
@Bean
public AccessDeniedHandler accessDeniedHandler() {
AccessDeniedHandler accessDeniedHandler = (request, response, e) -> {
ResponseMsg<String> responseMsg = new ResponseMsg<>();
responseMsg.setStatus(false);
responseMsg.setBody(e.getMessage());
responseMsg.setErrorCode(SystemErrorCode.NO_PERMISSION);
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
response.getWriter().write(JSONObject.toJSONString(responseMsg));
};
return accessDeniedHandler;
} /**
* 登录成功后的处理
* @return
*/
@Bean
public AuthenticationSuccessHandler authenticationSuccessHandler() {
AuthenticationSuccessHandler authenticationSuccessHandler = (request, response, authentication) -> {
//返回数据
ResponseMsg<List<MenuDTO>> responseMsg = new ResponseMsg<>();
responseMsg.setBody(userService.getMenus());
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
response.getWriter().write(JSONObject.toJSONString(responseMsg));
};
return authenticationSuccessHandler;
} /**
* 登录失败后的处理
* @return
*/
@Bean
public AuthenticationFailureHandler authenticationFailureHandler() {
AuthenticationFailureHandler authenticationFailureHandler = (request, response, e) -> {
ResponseMsg<String> responseMsg = new ResponseMsg<>();
responseMsg.setStatus(false);
responseMsg.setBody(e.getMessage());
responseMsg.setErrorCode(SystemErrorCode.ACCOUNT_ERROR);
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
response.getWriter().write(JSONObject.toJSONString(responseMsg));
};
return authenticationFailureHandler;
} /**
* 登出成功后的处理
* @return
*/
@Bean
public LogoutSuccessHandler logoutSuccessHandler() {
LogoutSuccessHandler logoutSuccessHandler = (request, response, authentication) -> {
ResponseMsg<String> responseMsg = new ResponseMsg<>();
responseMsg.setStatus(true);
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
response.getWriter().write(JSONObject.toJSONString(responseMsg));
};
return logoutSuccessHandler;
}
}

  其他的就不详细介绍了,基本上都是怎么样去处理,在具体的接入点出现的问题。

  7、登录、登出

  登录默认的参数为username、password 采用表单方式提交。如果需要修改参数名称可以在loginPage后面加入

.usernameParameter("name")
.passwordParameter("pwd")

  说明:默认登录、登出配置的接口不需要实现,默认也是放开的。

  8、无需验证访问

  在自己开发接口的时候肯定不需要进行权限的访问,这个时候就可以通过配置方式放开具体的请求在.authorizeRequests()配置

.antMatchers("/api/user/register").permitAll()

  9、默认会话超时30分钟,可以通过配置修改会话保存时间

server:
servlet:
session:
timeout: 1800s

springboot对security的后端配置的更多相关文章

  1. SpringBoot + Spring Security 学习笔记(一)自定义基本使用及个性化登录配置

    官方文档参考,5.1.2 中文参考文档,4.1 中文参考文档,4.1 官方文档中文翻译与源码解读 SpringSecurity 核心功能: 认证(你是谁) 授权(你能干什么) 攻击防护(防止伪造身份) ...

  2. spring boot + spring security +前后端分离【跨域】配置 + ajax的json传输数据

    1.前言 网上各个社区的博客参差不齐 ,给初学者很大的困扰 , 我琢磨了一天一夜,到各个社区找资料,然后不断测试,遇到各种坑,一言难尽啊,要么源码只有一部分,要么直接报错... 最后实在不行,直接去看 ...

  3. AgileBoot - 基于SpringBoot + Vue3的前后端快速开发脚手架

    AgileBoot 仓库 后端地址:https://github.com/valarchie/AgileBoot-Back-End 技术栈:Springboot / Spring Security / ...

  4. SpringBoot + Spring Security 学习笔记(五)实现短信验证码+登录功能

    在 Spring Security 中基于表单的认证模式,默认就是密码帐号登录认证,那么对于短信验证码+登录的方式,Spring Security 没有现成的接口可以使用,所以需要自己的封装一个类似的 ...

  5. SpringBoot + Spring Security 学习笔记(三)实现图片验证码认证

    整体实现逻辑 前端在登录页面时,自动从后台获取最新的验证码图片 服务器接收获取生成验证码请求,生成验证码和对应的图片,图片响应回前端,验证码保存一份到服务器的 session 中 前端用户登录时携带当 ...

  6. 基于Springboot集成security、oauth2实现认证鉴权、资源管理

    1.Oauth2简介 OAuth(开放授权)是一个开放标准,允许用户授权第三方移动应用访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方移动应用或分享他们数据的所有内容,OAu ...

  7. springboot+spring security +oauth2.0 demo搭建(password模式)(认证授权端与资源服务端分离的形式)

    项目security_simple(认证授权项目) 1.新建springboot项目 这儿选择springboot版本我选择的是2.0.6 点击finish后完成项目的创建 2.引入maven依赖  ...

  8. SpringBoot中使用UEditor基本配置(图文详解)

    SpringBoot中使用UEditor基本配置(图文详解) 2018年03月12日 10:52:32 BigPotR 阅读数:4497   最近因工作需要,在自己研究百度的富文本编辑器UEditor ...

  9. SpringBoot:配置文件及自动配置原理

    西部开源-秦疆老师:基于SpringBoot 2.1.6 的博客教程 秦老师交流Q群号: 664386224 未授权禁止转载!编辑不易 , 转发请注明出处!防君子不防小人,共勉! SpringBoot ...

随机推荐

  1. Sublime Text 3中设置不记住上次打开的文件

    转自:https://blog.csdn.net/nicholaszao/article/details/79575251 在”User/Preferences.sublime-settings”配置 ...

  2. Java50道经典习题-程序21 求阶乘

    题目:求1+2!+3!+...+20!的和分析:使用递归求解 0的阶乘和1的阶乘都为1 public class Prog21{ public static void main(String[] ar ...

  3. 2019.3.26 为什么说HTTP是无状态协议/无连接

    无状态 1.协议对于事务处理没有记忆能力 2.对同一个url请求没有上下文关系 3.每次的请求都是独立的,它的执行情况和结果与前面的请求和之后的请求时无直接关系的,它不会受前面的请求应答情况直接影响, ...

  4. Spring(十四)之事务

    事务管理 一个数据库事务是一个被视为单一的工作单元的操作序列.这些操作应该要么完整地执行,要么完全不执行.事务管理是一个重要组成部分,RDBMS 面向企业应用程序,以确保数据完整性和一致性.事务的概念 ...

  5. Eclipse配置多个Tomcat服务器

    我们在开发大型web项目时,经常需要在eclipse中同时启动多个tomcat服务器来开启多个服务.这里讲解一下如何在eclipse中配置多个tomcat服务器. 配置步骤 1. 在tomcat官网( ...

  6. PL/SQL Developer编码格式设置

    通过PL/SQL中文字段显示乱码或者导出数据出现乱码,原因是数据库的编码格式和PL/SQL的编码格式不统一导致. 查看ORACLE数据库字符集: select userenv('language') ...

  7. 模块XXXX可能与您正在运行的Windows版本不兼容。检查该模块是否与regsvr32.exe的x86(32位)x64(64位)版本兼容。

    最近自己在编写ActiveX控件.遇到的麻烦事不少. 今天遇到了这个问题“模块XXXX可能与您正在运行的Windows版本不兼容.检查该模块是否与regsvr32.exe的x86(32位)x64(64 ...

  8. 学习使用 ARM 的 math 库,据说 速度比C标准库 自带的 快 几十倍 到几百倍

    1.首先 添加 库 到 工程 ,路径 如下 C:\Keil\ARM\CMSIS\Lib\ARM 2.包含头文件以及在 工程里 添加 头文件 路径如下  C:\Keil\ARM\CMSIS\Includ ...

  9. react中如何获取onclick事件调用元素的dom对象

    今天终于有时间写博客了, 前几天项目有个需求,我感觉用dom操作兄弟元素实现比较方便,但是前端用的react框架不能用jquery的$(this)获取当前元素,查了好多资料和尝试后写下总结: 在HTM ...

  10. 笔记:HTML5中input元素新增的type值

    在HTML5中,input元素的type值增加了不少,使input的功能强大了很多. 但在各大浏览器中并不是所有的type值都支持. 以下是比较有用.并且浏览器支持的稍好一些的值: type=colo ...