springboot对security的后端配置
一、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父类AbstractUserDetailsAuthenticationProvider中hideUserNotFoundExceptions为true
解决方式重新配置: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的后端配置的更多相关文章
- SpringBoot + Spring Security 学习笔记(一)自定义基本使用及个性化登录配置
官方文档参考,5.1.2 中文参考文档,4.1 中文参考文档,4.1 官方文档中文翻译与源码解读 SpringSecurity 核心功能: 认证(你是谁) 授权(你能干什么) 攻击防护(防止伪造身份) ...
- spring boot + spring security +前后端分离【跨域】配置 + ajax的json传输数据
1.前言 网上各个社区的博客参差不齐 ,给初学者很大的困扰 , 我琢磨了一天一夜,到各个社区找资料,然后不断测试,遇到各种坑,一言难尽啊,要么源码只有一部分,要么直接报错... 最后实在不行,直接去看 ...
- AgileBoot - 基于SpringBoot + Vue3的前后端快速开发脚手架
AgileBoot 仓库 后端地址:https://github.com/valarchie/AgileBoot-Back-End 技术栈:Springboot / Spring Security / ...
- SpringBoot + Spring Security 学习笔记(五)实现短信验证码+登录功能
在 Spring Security 中基于表单的认证模式,默认就是密码帐号登录认证,那么对于短信验证码+登录的方式,Spring Security 没有现成的接口可以使用,所以需要自己的封装一个类似的 ...
- SpringBoot + Spring Security 学习笔记(三)实现图片验证码认证
整体实现逻辑 前端在登录页面时,自动从后台获取最新的验证码图片 服务器接收获取生成验证码请求,生成验证码和对应的图片,图片响应回前端,验证码保存一份到服务器的 session 中 前端用户登录时携带当 ...
- 基于Springboot集成security、oauth2实现认证鉴权、资源管理
1.Oauth2简介 OAuth(开放授权)是一个开放标准,允许用户授权第三方移动应用访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方移动应用或分享他们数据的所有内容,OAu ...
- springboot+spring security +oauth2.0 demo搭建(password模式)(认证授权端与资源服务端分离的形式)
项目security_simple(认证授权项目) 1.新建springboot项目 这儿选择springboot版本我选择的是2.0.6 点击finish后完成项目的创建 2.引入maven依赖 ...
- SpringBoot中使用UEditor基本配置(图文详解)
SpringBoot中使用UEditor基本配置(图文详解) 2018年03月12日 10:52:32 BigPotR 阅读数:4497 最近因工作需要,在自己研究百度的富文本编辑器UEditor ...
- SpringBoot:配置文件及自动配置原理
西部开源-秦疆老师:基于SpringBoot 2.1.6 的博客教程 秦老师交流Q群号: 664386224 未授权禁止转载!编辑不易 , 转发请注明出处!防君子不防小人,共勉! SpringBoot ...
随机推荐
- Vue Spa切换页面时更改标题
在Vue组件化开发过程中,因为是单页面开发,但是有时候需要页面的title根据情况改变,于是上网查了一下,各种说法花(wo)里(kan)胡(bu)哨(dong), 于是想到一个黑科技 documet. ...
- Vcenter虚拟化三部曲----SQL Server 2008 R2 数据库安装
操作系统 Windows server 2008 R2 数据库 SQL Server 2008 R2 注意:SQL Server 2008 R2需要操作系统首先安装.NET Frame ...
- [iOS]UIDynamicAnimator动画
创建动画 UIDynamicAnimator *animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; 协议代理 ...
- #leetcode刷题之路22-括号生成
给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合. 例如,给出 n = 3,生成结果为:[ "((()))", "(()())&q ...
- ImageMagick使用小结
#查看是否安装imagemagick sudo apt list | grep imagemagick #安装imagemagick sudo apt-get install imagemagick ...
- 在Java中发送http的post请求,设置请求参数等等
前几天做了一个定时导入数据的接口,需要发送http请求,第一次做这种的需求,特地记一下子, 导包 import java.text.SimpleDateFormat;import java.util. ...
- [教学] Delphi IDE 文件搜寻功能
Delphi IDE 提供了一个方便的文件搜寻功能,操作如下: 点 Search 选单内的 Find in Files... 例如我们想搜寻 JFile 需要引用那一个源码,可输入如下: 输入关键字: ...
- pomelo 的一些监控和维护插件(工具)
POMELO 提供了非常多的插件,可以方便我们日常对其的一些操作和开发工作,同样的我们也可以自己开发一些定制的插件让其伴随整个POMELO的生命周期运作(这里 不是要介绍如何制作POMELO插件),这 ...
- Quick find Helper
using System; using Microsoft.Xrm.Sdk; using Microsoft.Crm.Sdk.Messages; /// <summary> /// 视图 ...
- oracle相关操作,存储、临时表空间、用户操作、启动过程
表空间:此空间是用来进行数据存储的(表.function.存储过程等),所以是实际物理存储区域.临时表空间:主要用途是在数据库进行排序运算[如创建索引.order by及group by.distin ...