Web应用的安全管理,包括两个方面:一是用户身份认证,即用户登录的设计;另一方面是用户的授权,即一个用户在一个应用系统中能够执行哪些操作的权限管理。我这里使用spring-cloud-security进行安全管理。

  首先是依赖配置

    <parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-parent</artifactId>
<version>Brixton.M5</version>
<relativePath/>
</parent> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency> </dependencies>

  安全策略配置

@Configuration
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
@EnableConfigurationProperties(SecuritySettings.class)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
protected Log log = LogFactory.getLog(getClass());
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private SecuritySettings settings;
@Autowired
private CustomUserDetailsService customUserDetailsService;
@Autowired @Qualifier("dataSource")
private DataSource dataSource; @Override
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.userDetailsService(customUserDetailsService).passwordEncoder(passwordEncoder());
//remember me
auth.eraseCredentials(false);
} @Override
protected void configure(HttpSecurity http) throws Exception {//setting是自定义的配置参数
http.formLogin().loginPage("/login").permitAll().successHandler(loginSuccessHandler())  //设定一个自定义的的登陆页面URL
.and().authorizeRequests()
.antMatchers("/images/**", "/checkcode", "/scripts/**", "/styles/**").permitAll()  //完全允许访问的一些URL配置
.antMatchers(settings.getPermitall().split(",")).permitAll()
.anyRequest().authenticated()
.and().csrf().requireCsrfProtectionMatcher(csrfSecurityRequestMatcher())  //跨站请求伪造,这是一个防止跨站请求伪造攻击的策略配置
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER)
.and().logout().logoutSuccessUrl(settings.getLogoutsuccssurl())  //设定登出成功的链接
.and().exceptionHandling().accessDeniedPage(settings.getDeniedpage())   //配置拒绝访问的提示链接
.and().rememberMe().tokenValiditySeconds(86400).tokenRepository(tokenRepository()); //用来记住用户的登录状态,用户没执行推出下次打开页面不用登陆,时效自己设置
} @Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
} @Bean
public JdbcTokenRepositoryImpl tokenRepository(){
JdbcTokenRepositoryImpl jtr = new JdbcTokenRepositoryImpl();
jtr.setDataSource(dataSource);
return jtr;
} @Bean
public LoginSuccessHandler loginSuccessHandler(){//设置登陆成功处理器
return new LoginSuccessHandler();
} @Bean
public CustomFilterSecurityInterceptor customFilter() throws Exception{
CustomFilterSecurityInterceptor customFilter = new CustomFilterSecurityInterceptor();
customFilter.setSecurityMetadataSource(securityMetadataSource());  
customFilter.setAccessDecisionManager(accessDecisionManager());
customFilter.setAuthenticationManager(authenticationManager);
return customFilter;
} @Bean
public CustomAccessDecisionManager accessDecisionManager() {//
return new CustomAccessDecisionManager();
} @Bean
public CustomSecurityMetadataSource securityMetadataSource() {
return new CustomSecurityMetadataSource(settings.getUrlroles());
} private CsrfSecurityRequestMatcher csrfSecurityRequestMatcher(){ //加入需要排除阻止CSRF攻击的链表链接,链接地址中包含/rest字符串的,对其忽略CSRF保护策略
CsrfSecurityRequestMatcher csrfSecurityRequestMatcher = new CsrfSecurityRequestMatcher();
List<String> list = new ArrayList<String>();
list.add("/rest/");
csrfSecurityRequestMatcher.setExecludeUrls(list);
return csrfSecurityRequestMatcher;
}
}

  自定义的securityconfig配置,放在application.yml中

securityconfig:
logoutsuccssurl: /
permitall: /rest/**,/bbs**
deniedpage: /deny
urlroles: /**/new/** = admin;
/**/edit/** = admin,editor;
/**/delete/** = admin

  权限管理规则

@ConfigurationProperties(prefix="securityconfig")
public class SecuritySettings {
private String logoutsuccssurl = "/logout";
private String permitall = "/api";
private String deniedpage = "/deny";
private String urlroles; public String getLogoutsuccssurl() {//定义推出成功的链接
return logoutsuccssurl;
} public void setLogoutsuccssurl(String logoutsuccssurl) {
this.logoutsuccssurl = logoutsuccssurl;
} public String getPermitall() {//定义允许访问的URL列表
return permitall;
} public void setPermitall(String permitall) {
this.permitall = permitall;
} public String getDeniedpage() {
return deniedpage;
} public void setDeniedpage(String deniedpage) {//定义拒绝访问的信息提示链接
this.deniedpage = deniedpage;
} public String getUrlroles() {
return urlroles;
} public void setUrlroles(String urlroles) {//链接地质与角色权限的配置列表
this.urlroles = urlroles;
}
}

  防攻击策略

public class CsrfSecurityRequestMatcher implements RequestMatcher {
protected Log log = LogFactory.getLog(getClass());
private Pattern allowedMethods = Pattern
.compile("^(GET|HEAD|TRACE|OPTIONS)$");
/**
* 需要排除的url列表
*/
private List<String> execludeUrls; @Override
public boolean matches(HttpServletRequest request) {
if (execludeUrls != null && execludeUrls.size() > 0) {
String servletPath = request.getServletPath();
for (String url : execludeUrls) {
if (servletPath.contains(url)) {
log.info("++++"+servletPath);
return false;
}
}
}
return !allowedMethods.matcher(request.getMethod()).matches();
} public List<String> getExecludeUrls() {
return execludeUrls;
} public void setExecludeUrls(List<String> execludeUrls) {
this.execludeUrls = execludeUrls;
}
}
public class CustomAccessDecisionManager implements AccessDecisionManager {
private static final Logger logger = Logger.getLogger(CustomAccessDecisionManager.class); @Override
public void decide(Authentication authentication, Object object,
Collection<ConfigAttribute> configAttributes)
throws AccessDeniedException, InsufficientAuthenticationException {
if (configAttributes == null) {
return;
} //config urlroles
Iterator<ConfigAttribute> iterator = configAttributes.iterator(); while (iterator.hasNext()) {
ConfigAttribute configAttribute = iterator.next();
//need role
String needRole = configAttribute.getAttribute();
//user roles
for (GrantedAuthority ga : authentication.getAuthorities()) {
if (needRole.equals(ga.getAuthority())) {
return;
}
}
logger.info("need role is " + needRole);
}
throw new AccessDeniedException("Cannot Access!");
} @Override
public boolean supports(ConfigAttribute configAttribute) {
return true;
} @Override
public boolean supports(Class<?> clazz) {
return true;
} }
public class CustomFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {
private static final Logger logger = Logger.getLogger(CustomFilterSecurityInterceptor.class);
private FilterInvocationSecurityMetadataSource securityMetadataSource; @Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
FilterInvocation fi = new FilterInvocation(request, response, chain);
logger.debug("===="+fi.getRequestUrl());
invoke(fi);
} public void invoke(FilterInvocation fi) throws IOException, ServletException {
InterceptorStatusToken token = super.beforeInvocation(fi);
try {
fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
} catch (Exception e) {
logger.error(e.getMessage());
} finally {
super.afterInvocation(token, null);
}
} public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {
return this.securityMetadataSource;
} @Override
public Class<? extends Object> getSecureObjectClass() {
return FilterInvocation.class;
} @Override
public SecurityMetadataSource obtainSecurityMetadataSource() {
return this.securityMetadataSource;
} public void setSecurityMetadataSource(
FilterInvocationSecurityMetadataSource smSource) {
this.securityMetadataSource = smSource;
} public void destroy() {
// TODO Auto-generated method stub } public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub } }
public class CustomSecurityMetadataSource implements FilterInvocationSecurityMetadataSource{
private static final Logger logger = Logger.getLogger(CustomSecurityMetadataSource .class); private Map<String, Collection<ConfigAttribute>> resourceMap = null;
private PathMatcher pathMatcher = new AntPathMatcher(); private String urlroles; @Override
public Collection<ConfigAttribute> getAllConfigAttributes() {
return null;
} public CustomSecurityMetadataSource (String urlroles) {
super();
this.urlroles = urlroles;
resourceMap = loadResourceMatchAuthority();
} private Map<String, Collection<ConfigAttribute>> loadResourceMatchAuthority() { Map<String, Collection<ConfigAttribute>> map = new HashMap<String, Collection<ConfigAttribute>>(); if(urlroles != null && !urlroles.isEmpty()){
String[] resouces = urlroles.split(";");
for(String resource : resouces){
String[] urls = resource.split("=");
String[] roles = urls[1].split(",");
Collection<ConfigAttribute> list = new ArrayList<ConfigAttribute>();
for(String role : roles){
ConfigAttribute config = new SecurityConfig(role.trim());
list.add(config);
}
//key:url, value:roles
map.put(urls[0].trim(), list);
}
}else{
logger.error("'securityconfig.urlroles' must be set");
} logger.info("Loaded UrlRoles Resources.");
return map; } @Override
public Collection<ConfigAttribute> getAttributes(Object object)
throws IllegalArgumentException {
String url = ((FilterInvocation) object).getRequestUrl(); logger.debug("request url is " + url); if(resourceMap == null)
resourceMap = loadResourceMatchAuthority(); Iterator<String> ite = resourceMap.keySet().iterator();
while (ite.hasNext()) {
String resURL = ite.next();
if (pathMatcher.match(resURL,url)) {
return resourceMap.get(resURL);
}
}
return resourceMap.get(url);
} public boolean supports(Class<?> clazz) {
return true;
}
}

Spring Boot安全设计的配置的更多相关文章

  1. spring boot web相关配置

    spring boot集成了servlet容器,当我们在pom文件中增加spring-boot-starter-web的maven依赖时,不做任何web相关的配置便能提供web服务,这还得归于spri ...

  2. 初识Spring Boot框架(二)之DIY一个Spring Boot的自动配置

    在上篇博客初识Spring Boot框架中我们初步见识了SpringBoot的方便之处,很多小伙伴可能也会好奇这个Spring Boot是怎么实现自动配置的,那么今天我就带小伙伴我们自己来实现一个简单 ...

  3. Spring Boot 2.0 配置图文教程

    摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 本章内容 自定义属性快速入门 外化配置 自动配置 自定义创建 ...

  4. Spring boot 的自动配置

    Xml 配置文件 日志 Spring Boot对各种日志框架都做了支持,我们可以通过配置来修改默认的日志的配置: #设置日志级别 logging.level.org.springframework=D ...

  5. spring boot多数据源配置(mysql,redis,mongodb)实战

    使用Spring Boot Starter提升效率 虽然不同的starter实现起来各有差异,但是他们基本上都会使用到两个相同的内容:ConfigurationProperties和AutoConfi ...

  6. Spring Boot SSL [https]配置例子

    前言 本文主要介绍Spring Boot HTTPS相关配置,基于自签证书实现: 通过本例子,同样可以了解创建SSL数字证书的过程: 本文概述 Spring boot HTTPS 配置 server. ...

  7. spring boot 系列之六:深入理解spring boot的自动配置

    我们知道,spring boot自动配置功能可以根据不同情况来决定spring配置应该用哪个,不应该用哪个,举个例子: Spring的JdbcTemplate是不是在Classpath里面?如果是,并 ...

  8. 转-spring boot web相关配置

    spring boot web相关配置 80436 spring boot集成了servlet容器,当我们在pom文件中增加spring-boot-starter-web的maven依赖时,不做任何w ...

  9. spring boot日志管理配置

    spring Boot在所有内部日志中使用Commons Logging,但是默认配置也提供了对常用日志的支持,如:Java Util Logging,Log4J,Log4J2和Logback.每种L ...

随机推荐

  1. java:面向对象(接口(续),Compareble重写,Comparator接口:比较器的重写,内部类,垃圾回收机制)

    接口: *接口定义:使用interface关键字 * [修饰符] interface 接口名 [extends 父接口1,父接口2...]{ * //常量的声明 * //方法的声明 * } *接口成员 ...

  2. Java:面向对象(继承,方法的重写(overide),super,object类及object类中方法的重写,父子类代码块执行顺序)

    继承: 1.继承是对某一匹类的抽象,从而实现对现实世界更好的建模. 2.提高代码的复用性. 3.extends(扩展),子类是父类的扩展. 4.子类继承父类可以得到父类的全部属性和方法.(除了父类的构 ...

  3. Linux (Ubuntu 18.04) 安装vim编辑器

    大家可以去Ubuntu官网下载桌面系统:https://ubuntu.com/download/desktop,虽然最新版是19.04,但是建议大家下载稳定版18.04.安装过程非常简洁,我使用的是V ...

  4. markdown-博客编辑

    1. 快捷键 2. 基本语法 2.1 字体设置斜体.粗体.删除线 2.2 分级标题 2.3 链接 2.4 分割线 2.5 代码块 2.6 引用 2.7 列表 2.8 表格 3. 常用技巧 3.1 换行 ...

  5. "在指定的 DSN 中,驱动程序和应用程序之间的体系结构不匹配" 问题总结

    最近C#连接ODBC数据源时,总是提示"[Microsoft][ODBC 驱动程序管理器] 在指定的 DSN 中,驱动程序和应用程序之间的体系结构不匹配",百度查询之后才知道原来是 ...

  6. nginx - 反向代理 - 配置文件模板 - nginx 代理tcp的服务 - 部署示意图

    danjan01deiMac:~ danjan01$ cat /usr/local/etc/nginx/nginx.conf|grep -v '^$' worker_processes 1; even ...

  7. 论文阅读 | Towards a Robust Deep Neural Network in Text Domain A Survey

    摘要 这篇文章主要总结文本中的对抗样本,包括器中的攻击方法和防御方法,比较它们的优缺点. 最后给出这个领域的挑战和发展方向. 1 介绍 对抗样本有两个核心:一是扰动足够小:二是可以成功欺骗网络. 所有 ...

  8. C#连接oracle数据库报错:OCIEnvCreate 失败,返回代码为 -1,但错误消息文本不可用

    原因大概是OracleOraDb11g_home1TNSListener服务没启动的原因 步骤一.停止并重新启动OracleOraDb11g_home1TNSListener服务,试一下是否可行. 如 ...

  9. jvm 调优工具 i

    https://blog.csdn.net/wait_notify/article/details/70268194 https://blog.csdn.net/a718515028/article/ ...

  10. 初次shell编程

    虽然说的是初次shell写xhell脚本,但是其实我也写了三.四个简单的脚本了.现在总结下写简单的shell脚本中遇到的一些小问题备忘一下吧. 首先是脚本文件是已.sh作为后缀的,可以先建一个.sh的 ...