提前感慨
啊~~~~~~~~~总算看到这个章节了,一个章节一个章节看下来,由于使用的是和教程中不同的版本,所以遇到了很多关于版本迭代的不同点,各种查资料,问网友,哈哈哈,但是收获满满。
8.1.1、对之前的动态配置权限的小改动
教程中又创建了一个新的项目,然后演示了我们之前写的那些权限模块如何去使用,我这里暂不po出那部分的代码。仅仅在之前的Demo项目中对于需要修改的部分做简单的记录,以免忘记。
首先我们在之前的章节中遗留了一个问题,如下图所示
直接看代码
首先修改授权配置提供器AuthorizeConfigProvider中的返回类型
package com.moss.securitycore.authorize;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
/**
* 授权配置提供器,各个模块和业务系统可以通过实现此接口向系统添加授权配置。
*
* @author lwj
*/
public interface AuthorizeConfigProvider {
/**
* 配置
*
* @param config 这个是配置类中的http.authorizeRequests()方法返回的对象
*/
// void config(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry config);
/**
* 配置
*
* @param config
* @return 返回的boolean表示配置中是否有针对anyRequest的配置。在整个授权配置中,
* 应该有且仅有一个针对anyRequest的配置,如果所有的实现都没有针对anyRequest的配置,
* 系统会自动增加一个anyRequest().authenticated()的配置。如果有多个针对anyRequest
* 的配置,则会抛出异常。
*/
boolean config(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry config);
}
修改权限配置提供器的默认实现类MossAuthorizeConfigProvider
package com.moss.securitycore.authorize;
import com.moss.securitycore.properties.SecurityConstants;
import com.moss.securitycore.properties.SecurityProperties;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.stereotype.Component;
/**
* 权限配置提供器
*
* @author lwj
*/
@Component
@Order(Integer.MIN_VALUE)
public class MossAuthorizeConfigProvider implements AuthorizeConfigProvider {
@Autowired
private SecurityProperties securityProperties;
@Override
public boolean config(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry config) {
config.antMatchers(
SecurityConstants.DEFAULT_UNAUTHENTICATION_URL,
SecurityConstants.DEFAULT_LOGIN_PROCESSING_URL_MOBILE,
securityProperties.getBrowser().getLoginPage(),
SecurityConstants.DEFAULT_VALIDATE_CODE_URL_PREFIX + "/*",
securityProperties.getBrowser().getSignUpUrl(),
SecurityConstants.DEFAULT_SESSION_INVALID_URL,
"/user/regist",
"/auth/*",
"/qqLogin/*",
SecurityConstants.DEFAULT_LOGIN_PROCESSING_URL_OPEN_ID,
SecurityConstants.DEFAULT_APP_SOCIAL_SIGNUP
).permitAll();
// 由于退出登录的URL没有配置默认值,所以在这里需要判断一下
if (StringUtils.isNotBlank(securityProperties.getBrowser().getSignOutUrl())) {
config.antMatchers(securityProperties.getBrowser().getSignOutUrl()).permitAll();
}
return false;
}
}
修改授权配置管理者实现类MossAuthorizeConfigManager
package com.moss.securitycore.authorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* 授权配置管理者实现类
* 用于把系统中的所有授权配置收集起来
*
* @author lwj
*/
@Component
public class MossAuthorizeConfigManager implements AuthorizeConfigManager {
@Autowired
private List<AuthorizeConfigProvider> authorizeConfigProviders;
/**
* @param config 这个是配置类中的http.authorizeRequests()方法返回的对象
* @see com.moss.securitycore.authorize.AuthorizeConfigManager#config(org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry)
*/
@Override
public void config(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry config) {
// 将所有的provider中配置的配置循环添加到项目的总配置中
boolean existAnyRequestConfig = false;
String existAnyRequestConfigName = null;
for (AuthorizeConfigProvider authorizeConfigProvider : authorizeConfigProviders) {
boolean currentIsAnyRequestConfig = authorizeConfigProvider.config(config);
if (existAnyRequestConfig && currentIsAnyRequestConfig) {
throw new RuntimeException("重复的anyRequest配置:" + existAnyRequestConfigName + ","
+ authorizeConfigProvider.getClass().getSimpleName());
} else if (currentIsAnyRequestConfig) {
existAnyRequestConfig = true;
existAnyRequestConfigName = authorizeConfigProvider.getClass().getSimpleName();
}
}
if (!existAnyRequestConfig) {
config.anyRequest().authenticated();
}
}
}
关键点!关键点!关键点!
重要的事情说三遍!上面的代码中包含的逻辑需要体会
然后下面的这段修改的代码中的中间的config配置也需要理解下;
下面我们配置了三种资源的不同权限要求
1.对于font资源我们使用了permitAll;因为这些是引用安全模块的系统中需要用到的资源文件,所以是不需要登录也可以被访问的
2.对于html页面和resource下的资源以及访问自身数据,是需要登录后才可以被访问
3.通过权限表达式的方式配置了一个从数据库中根据登录用户来动态获取数据,来判断用户是否有权限可以访问该资源
下面的三个配置中1和2并未在Demo项目中体现,这里主要式为了做例子展示。
package com.moss.securitydemo.security;
import com.moss.securitycore.authorize.AuthorizeConfigProvider;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.stereotype.Component;
/**
* Demo项目的权限配置管理器
*
* @author lwj
*/
@Component
@Order(Integer.MAX_VALUE)
public class DemoAuthorizeConfigProvider implements AuthorizeConfigProvider {
@Override
public boolean config(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry config) {
config
.antMatchers(HttpMethod.GET, "/fonts/**").permitAll()
.antMatchers(HttpMethod.GET,
"/**/*.html",
"/admin/me",
"/resource").authenticated()
.anyRequest()
.access("@rbacService.hasPermission(request, authentication)");
// 配置数据库的URL
config.anyRequest().access("@rbacService.hasPermission(request,authentication)");
// 由于上一行代码设置的是一个anyRequest所以这里需要设置返回为true
return true;
}
}
8.1.2、结语
代码千万行,我们需要去提升的是规范别人写代码的能力,而不是但一个学习一个功能的实现;就像授人以鱼不如授人以渔!