保护你的应用程序安全:使用Spring Security数据库
随着互联网的发展,越来越多的人选择在网络上完成他们的事务。应用程序的使用也显著增加,其中包括银行账户和社交媒体等重要的应用程序。然而,与其相关的风险也在增加。黑客和其他恶意用户正在寻找漏洞,以便盗取用户的敏感信息。因此,开发人员必须采取适当的措施来保护他们的应用程序免受攻击。
Spring Security是一个开源框架,可以帮助开发人员在应用程序中实施身份验证和授权。这个框架包含了许多内置的安全功能,可以防止诸如跨站点请求伪造和SQL注入等攻击。 Spring Security 还允许开发人员自定义安全策略,并提供了易于使用的API和工具,使其成为开发安全应用程序的理想选择。
在实施安全措施时,应用程序的开发人员应该选择合适的数据库来存储用户和权限信息。 Spring Security提供了多种选项,包括使用内存,LDAP,JDBC和自定义用户详细信息存储。其中,JDBC用户详细信息存储被广泛采用,因为它提供了与传统关系数据库的集成。这种方法也允许开发人员通过SQL查询查询数据。
在本文中,我们将重点介绍如何使用Spring Security数据库来保护你的应用程序。我们将介绍如何设置安全配置,配置数据源,创建用户和角色,以及如何使用Spring Security框架以确保数据的安全性。
*** 设置安全配置
在使用Spring Security数据库之前,我们需要配置Spring Security的安全性。为此,我们需要创建一个类,该类在应用程序启动时加载,并配置安全策略。对于这个例子,我们将创建一个名为WebSecurityConfig的类。
以下是WebSecurityConfig类的核心代码:
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated().and().formLogin()
.loginPage(“/login”).permitAll().and().logout().permitAll();
}
}
在此设置中,我们定义了一组规则,以确定哪些请求需要进行身份验证。在任何请求( anyRequest() )中,我们必须通过身份验证,否则将重定向到登录页面( loginPage(“/login”) )。我们还配置了一个注销功能,使用户能够退出应用程序。
*** 配置数据源
接下来,我们需要配置数据库作为用户详细信息的存储库。为此,我们需要设置一个数据源,该数据源将与Spring Security库集成。
以下是WebSecurityConfig类中配置数据源的代码示例:
@Configuration
public class DataSourceConfig {
@Autowired
@Qualifier(“securityDataSource”)
DataSource dataSource;
@Bean
public JdbcUserDetlsManager jdbcUserDetlsManager() {
JdbcUserDetlsManager jdbcUserDetlsManager = new JdbcUserDetlsManager();
jdbcUserDetlsManager.setDataSource(dataSource);
return jdbcUserDetlsManager;
}
}
在此示例中,我们使用JdbcUserDetlsManager,它是Spring Security的内置用户管理器。我们需要将数据源设置为JdbcUserDetlsManager的输入,以便向其提供用户详细信息。
*** 创建用户和权限
我们现在已经创建了安全配置并配置了数据源,接下来我们需要创建用户和角色。
以下代码示例演示如何使用Spring Security JDBC用户详细信息存储来创建新用户:
@Autowired
public void configureUserDetlsService(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication().dataSource(dataSource)
.usersByUsernameQuery(
“select username,password,enabled from users where username=?”)
.authoritiesByUsernameQuery(
“select username, authority from authorities where username=?”);
}
在此示例中,我们使用Spring Security的AuthenticationManagerBuilder,使用了JDBC用户详细信息存储来设置数据库的查询。我们指定了两个SQL语句,用于获取用户的详细信息和权限信息。
我们还可以使用JdbcUserDetlsManager来创建用户。以下是一个创建用户的示例代码:
@Autowired
JdbcUserDetlsManager jdbcUserDetlsManager;
@RequestMapping(value = “/addUser”, method = RequestMethod.POST)
public String addUser(@RequestParam(“username”) String username, @RequestParam(“password”) String password) {
jdbcUserDetlsManager.createUser(User.withUsername(username).password(passwordEncoder().encode(password))
.roles(“USER”).build());
return “redirect:/home”;
}
在此示例中,我们使用JdbcUserDetlsManager的createUser功能,将新用户添加到数据库中。请注意,密码被编码以确保安全性。
*** 使用Spring Security框架
有了安全配置,数据源和用户和角色,我们现在可以使用Spring Security框架来保护我们的应用程序。在此示例中,我们将演示如何使用Spring Security来控制对REST API的访问。
以下是一个演示如何使用Spring Security来保护REST API的示例代码:
@Configuration
public class ServerSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers(HttpMethod.POST, “/api/**”).hasRole(“ADMIN”)
.anyRequest().permitAll()
.and()
.csrf().disable()
.httpBasic();
}
}
在此示例中,我们使用Spring Security的configure函数,使得只有具有ADMIN角色的用户可以使用HTTP POST访问REST API。这种方法将确保敏感信息保持安全,并防止未经授权的用户进行恶意攻击。
*** 结论
使用Spring Security数据库可以有效保护你的应用程序。在本文中,我们介绍了如何设置安全配置,配置数据源,创建用户和角色,并在应用程序中使用Spring Security框架来控制访问权限。这种方法可以确保用户和敏感数据的安全,并防止未经授权的访问。开发人员必须为他们的应用程序选择正确的数据库,以确保其功能的完整性和系统的安全性。
相关问题拓展阅读:
- 在spring security3中启用用户的缓存功能后,如何去测试缓存已经发挥作用?
- 使用spring security框架打开页面怎么这么慢
- 单点登录JWT与Spring Security OAuth
在spring security3中启用用户的缓存功能后,如何去测试缓存已经发挥作用?
测试别的类试试吧,user权限信息会放到SecurityContextHolder里
使用spring security框架打开页面怎么这么慢
慢,这是很正常的,旁迅很自然的,
不值得运李此大惊小怪的扰团、以偏概全的。
任何机子都有缓冲的过程,
何况这个框架,
等待才是硬道理。
等待的过程中可以玩玩游戏来消磨时间。
SpringSecurity如何控制权限概要Spring使用由Filter组成的Chain,来判断权限。如下图所示:Spring预定义了很多out-of-boxedfilter供开发者直接使用。每个Filter一般情况下(有些Filter是abstract的),都和配置文件的一个元素(有的情况下可能是属性)对应。比如:AUTHENTICATION_PROCESSING_FILTER,对应配置文件里面的:http/form-login元素。如果Spring提供的Filter不能满足系统的权限功能,开发者可以自定义Filter,然后把Filter放在某个FilterChain的某个位置。可以替换掉原有FilterChain的某个Filter,也可以放在某个Filter之前或者之后。总之,SpringSecurity采用FilterChain模式判断权限,Spring提供了一些Filter,也支持开发者自定义Filter。与WEB系统的集成使用JavaEE的Filter(非Spring的Filter)机制,将需要权限判断的url,“牵引”给Spring的FilterChain即可。一般情况下,将所有的url都引入FilterChain。当然也可以在web.xml配置需要权限判断的url(配置filter-mapping/url-pattern)。Spring的配置文件也支持过滤掉不需要权限判断的url(配置http/intercept-url元素)。控制内容SpringSecurity提供了如下内容的控制:1.url;2.beanmethod;3.httpsession。url:可以分为需要权限判断的url,不需要权限判断的url,登录表单url。通过我对spring相关帖子和参考文档的阅读,需要权限判断的url。仅限于做角色判断,就是说判断当前用户是否具有指定的角色。beanmethod:Spring支持对Servicelayermethod做权限判断。通过我对spring相关帖子和参考文档的阅读,也仅限于做角色判断。配置方式有2种:1.写在Java源代码里面,如:@Secured(“ROLE_TELLER”)(该方法只有具有TELLER角色的用户能够访问,否则抛出异常);2.写在配置文件里面,如:(该bean的所有set方法,只有具有ADMIN角色的用户能够访问,否则抛出异常)。httpsession:控制一个用户名是否能重复登录,以及重复登录次数,并非重试密码次数。另外,SpringSecurity还提供了如下一些功能:1.rememberme,记住我;2.form-login登录控制;3.多种身份认证功能;4.用户密码加密和“salt”功能;5.http协议控制;6.访问端口控制;7.Pre-Invocation&After-Invocation。rememberme,记住我:还记得浏览器采用cookie记住用户名和密码自动登录吗?好像就是这个(不知道我理解错了没有,应该没有。只是我不大敢相信)。使用这个功能,开发者在登录页面,使用spring自定义的标签。form-login登录控制:有些页面不允许匿名访问,那么当匿名访问这些页面的滑野时候,将弹出(或者转到)form-login窗口(或者页面)。这里又牵引出2个问题:1,输入用户名和密码后怎样验证;2,密码是否需要加密,怎么加密。多种身份认证功能:Spring提供了丰富的用户身份认证功能。身份认证是什么意思?比如您告诉我“我是神仙”。那么我会问您“凭什么证明您是神仙”。这就是身份认证。认证手段一般是保存到数据库表的用户名/密码,ukey,ldap等。一般情况下,我们都使用用户名/密码的。用户密码加密和“salt”功能:密码采用md5,还是sha加密算法。如果我们对密码加密的时候,不想仅仅对密码加密,还想把用户名和密码信伍喊放在一起加密做为加密后的密码。那么使用salt吧。salt支持也读取用户的其他属性,不仅是用户名。http协议控制:哪些url,必须采用https访问呢?哪些url必须采用http访问呢?哪些又两者都可以呢?通过这个配橘胡置。访问端口控制:类似http协议控制,控制url和访问端口之间的关系。Pre-Invocation&After-Invocation:在方法调用之前做权限判断,还是方法调用之后做权限判断呢?一般情况下是之前调用。也有情况下是之后调用。具体例子可以看官方文档(22.3小节)。细粒度权限控制由上面分析,我们看到url、method的权限判断,都仅限于用户角色权限判断。事实上Spring使用投票(Voter)机制,来做权限判断。用户角色权限也是一种投票。投票这个词,听起来不容易懂。举例:董事会开会,各个股东投票以表决决议是否通过。Spring的角色投票器,只会投出一票。我们平时所说的投票至少要2张票吧,一张还叫什么投票。Spring的投票有3种结果:允许、拒绝和弃权。弃权?真的有点晕。呵呵,这种情况下还弃权。那么投票器,如何集成到Spring的Filter里面呢?Spring的Filter一般都由一个Manager支撑着。比如accessDecisionManager,可以由RoleVoter和BasicAclEntryVoter提供投票。accessDecisionManager根据RoleVoter,BasicAclEntryVoter投票结果,做出决策判断。细粒度(数据级)的权限控制,SpringSecurity提供了一种模型以及相关实现。下面我简要说说这个模型。举例:张三授权查询华北区域客户资料,李四授权查询华南区域客户资料。那么,首先会对所有客户记录做个标示(相当于取个id),然后在acl-entry表给张三授权华北所有客户访问权限;给李四华南区域所有客户权限。表记录大致是这样的:访问用户被访问数据授权操作张三华北电力客户1读取张三华北电力客户2读取李四华南电力客户1读取………这个模型的缺点是非常明显的:1.和业务数据绑定死了,业务数据的增/删,需要维护该权限表;2.在大数据量的情况下,系统效率低下。因此,开发者需要自己书写投票器了。我们理想中的权限管理客户对权限管理的需求这里是指我们服务的最终用户,而不是软件开发者。客户对权限管理的需求,大体可以概括如下:1.自主灵活地管理角色、角色权限,并将角色赋予系统相关用户;2.数据安全。系统展现数据是满足权限的,在系统内部搜索数据也必须在相应权限访问内,对系统数据进行增加、修改、删除必须是满足权限的;3.没有功能的按钮、菜单、数据等等,就不要在界面上出现了。开发中遇到的难点管理用户、角色、权限,以及三者之间的关系,这种典型的RBAC模型,非常容易,没有任何困难。困难的是,数据级权限控制。这是和业务直接挂钩的,最复杂,而且会经常因为客户需求表达不到位、开发人员需求理解不到位、系统框架库表结构发生变化,而不断变化的。这种变化,不仅需要编码,而且还需要重新测试。甚至这种变化会波及到其他模块,甚至整个系统。系统开发经历几次变化下来,代码里面散布着if/else,散布着sql语句。导致badell。我们理想的权限管理我们期望的权限管理,应该具有这么几个特性:1.能实现角色级权限;能实现数据级权限;2.简单、易操作,能够应对各种需求;3.应对需求变更能力强;4.更好有相关界面,比如权限管理界面、角色管理界面,角色和权限关系维护界面,用户和角色关系维护界面。如果没有界面,也是可以接受的。毕竟这些页面需要最终用户来使用,不同用户对系统的界面要求不同。因此我们并不期望统一的管理界面。SpringSecurity的评价在SpringSecurity世界里,可以区分出哪些资源可以匿名访问,哪些需要角色权限,又是哪个页面提供登录功能;怎样进行用户身份认证,用户的密码如何加密。哪些资源必须使用https协议,资源和访问端口有怎样的对应关系。下面就优点和缺点对SpringSecurity进行点评。优点总体说来SpringSecurity具有以下几个优点:1.提供了一套权限框架,这套框架是可行的;2.提供了很多用户身份认证功能,可以节约大量开发工作;3.提供了角色判断功能,这点既是优点又是缺点;4.提供了form-login、rememberme等控制。其中2、4两点,对于我们中国开发者(我对国外系统不大了解),可用性并不大。我们的系统大多采用用户名/密码身份认证模式,大多公司都有可复用代码。form-login、rememberme等这些功能,并不是难以开发,而且可用之处也并不多。缺点我个人认为SpringSecurity存在以下几个硬伤:1.角色被“编码”到配置文件和源文件,这样最终用户就不能创建角色了。但最终用户期望自己来控制角色。因为在项目实施过程中,客户可能并不能确定有哪些角色,以及角色怎么分配给系统用户。角色大多需要等到系统上线后,才能确定。这些编码有:a)url的权限控制,;b)java方法的权限控制,@Secured(“IS_AUTHENTICATED_ANONYMOUS”);c)java方法的权限控制,;2.RBCA这种被广泛运用的模型,没有在SpringSecurity体现出来;3.SpringSecurity没有提供好的细粒度(数据级)权限方案,提供的缺省实现维护工作量大,在大数据量情况下,几乎不可用;4.SpringSecurity对于用户、角色、权限之间的关系,没有提供任何一种维护界面。不过从SpringSecurity角度看,确实没有必要有界面。角色创建、角色和权限直接的关系,都被“编码”到配置文件和源文件了;5.SpringSecurity学习难度大,配置文件还是很多。我承认有很多高手,但我们也看到有很多新人加入软件开发领域。付出如此大的学习代价,获得这么一点点好处,个人觉得并不值得。附言:本人在JavaEye创建“权限管理”圈子快2周了,吸引不少网友进来。我感到很高兴,也很荣幸。由于SpringSecurity运用范围还是比较广的,所以我打算好好学习一下,把学习经验和大家分享一下。
单点登录JWT与Spring Security OAuth
通过 JWT 配合 Spring Security OAuth2 使用的方式,可以避免
每次请求
都
远程调度
认证授权服务。
资源服务器
只需要从
授权服务器
验证一次,返回 JWT。返回的 JWT 包含了
用户
的所有信息,包括
权限信息
。
1. 什么是JWT
ON Web Token(JWT)是一种开放的标准(RFC 7519),JWT 定义了一种
紧凑
且
自包含
的标准,旨在将各个主体的信息包装为 ON 对象。
主体信息
是通过
数字签名
进行
加密
和
验证
的。经常使用 HMAC 算法或 RSA(
公钥
/
私钥
的
非对称性加密
)算法对 JWT 进行签名,
安全性谨首很高
。
2. JWT的结构
JWT 的结构由三部分组成:Header(头)、Payload(有效负荷)和 Signature(签名)。因此 JWT 通常的格式是 xxxxx.yyyyy.zzzzz。
2.1. Header
Header 通常是由
两部分
组成:令牌的
类型
(即 JWT)和使用的
算法类型
,如 HMAC、SHA256 和 RSA。例如:
将 Header 用 Base64 编码作为 JWT 的
之一部分
,不建议在 JWT 的 Header 中放置
敏感信息
。
2.2. Payload
下面是 Payload 部分的一个示例:
将 Payload 用 Base64 编码作为 JWT 的
第二部分
,不建议在 JWT 的 Payload 中放置
敏感信息
。
2.3. Signature
要创建签名部分,需要利用
秘钥
对 Base64 编码后的 Header 和 Payload 进行
加密
,加密算法的公式如下:
签名
可以用清慎于验证
消息
在
传递过程
中有没有被更改。对于使用
私钥签名
的 token,它还可以验证 JWT 的
发送方
是否为它所称的
发送方
。
3. JWT的工作方式
客户端
获取 JWT 后,对于以后的
每次请求
,都不需要再通过
授权服务
来判断该请求的
用户
以及该
用户的权限
。在微服务系统中,可以利用 JWT 实现
单点登录
。认证流程图如下:
4. 案例工程结构
工程原理示意图如下:
5. 构建auth-service授权服务
UserServiceDetail.java
UserRepository.java
实体类 User 和上一篇文章的内容一样,需要实现 UserDetails 接口,实体类 Role 需要实现 GrantedAuthority 接口。
User.java
Role.java
jks 文件的生成需要使用 Java keytool 工具,保证 Java 环境变量没问题,输入命令如下:
其中,-alias 选项为
别名
,-keyalg 为
加密算法
,-keypass 和 -storepass 为
密码选项
,-keystore 为 jks 的
文件名称
,-validity 为配置 jks 文件
过期时间
(单位:天)。
生成的 jks 文件作为
私钥
,只允许
授权服务
所持有,用作
加密生成
JWT。把生成的 jks 文件放到 auth-service 模块的 src/main/resource 目录下即可。
对于 user-service 这样的
资源服务
,需要使用 jks 的
公钥
对 JWT 进行
解密
。获取 jks 文件的
公钥
的命令如下:
这个命令要求安装 openSSL 下载地址,然后手动把安装的 openssl.exe 所在目录配置到
环境变量
。
输入密码 fzp123 后,显示的信息很多,只需要提取 PUBLIC KEY,即如下所示:
新建一个 public.cert 文件,将上面的
公钥信息
复制到 public.cert 文件中并保存。祥正数并将文件放到 user-service 等
资源服务
的 src/main/resources 目录下。至此 auth-service 搭建完毕。
maven 在项目编译时,可能会将 jks 文件
编译
,导致 jks 文件
乱码
,最后不可用。需要在 pom.xml 文件中添加以下内容:
6. 构建user-service资源服务
注入 JwtTokenStore 类型的 Bean,同时初始化 JWT 转换器 JwtAccessTokenConverter,设置用于解密 JWT 的
公钥
。
配置
资源服务
的认证管理,除了
注册
和
登录
的接口之外,其他的接口都需要
认证
。
新建一个配置类 GlobalMethodSecurityConfig,通过 @EnableGlobalMethodSecurity 注解开启
方法级别
的
安全验证
。
拷贝 auth-service 模块的 User、Role 和 UserRepository 三个类到本模块。在 Service 层的 UserService 编写一个
插入用户
的方法,代码如下:
配置用于用户密码
加密
的工具类 BPwdEncoderUtil:
实现一个
用户注册
的 API 接口 /user/register,代码如下:
在 Service 层的 UserServiceDetail 中添加一个 login() 方法,代码如下:
AuthServiceClient 作为 Feign Client,通过向 auth-service 服务接口 /oauth/token 远程调用获取 JWT。在请求 /oauth/token 的 API 接口中,需要在
请求头
传入 Authorization 信息,
认证类型
( grant_type )、用户名 ( username ) 和
密码
( password ),代码如下:
其中,AuthServiceHystrix 为 AuthServiceClient 的
熔断器
,代码如下:
JWT 包含了 access_token、token_type 和 refresh_token 等信息,代码如下:
UserLoginDTO 包含了一个 User 和一个 JWT 成员属性,用于返回数据的实体:
登录异常类 UserLoginException
全局异常处理
切面类 ExceptionHandle
在 Web 层的 UserController 类中新增一个登录的 API 接口 /user/login 如下:
依次启动 eureka-service,auth-service 和 user-service 三个服务。
7. 使用Postman测试
因为没有权限,访问被拒绝。在数据库手动添加 ROLE_ADMIN 权限,并与该用户关联。重新登录并获取 JWT,再次请求 /user/foo 接口。
在本案例中,用户通过
登录接口
来获取
授权服务
加密后的 JWT。用户成功获取 JWT 后,在以后每次访问
资源服务
的请求中,都需要携带上 JWT。
资源服务
通过
公钥解密
JWT,
解密成功
后可以获取
用户信息
和
权限信息
,从而判断该 JWT 所对应的
用户
是谁,具有什么
权限
。
获取一次 Token,多次使用,
资源服务
不再每次访问
授权服务
该 Token 所对应的
用户信息
和用户的
权限信息
。
一旦
用户信息
或者
权限信息
发生了改变,Token 中存储的相关信息并
没有改变
,需要
重新登录
获取新的 Token。就算重新获取了 Token,如果原来的 Token 没有过期,仍然是可以使用的。一种改进方式是在登录成功后,将获取的 Token
缓存
在
网关上
。如果用户的
权限更改
,将
网关
上缓存的 Token
删除
。当请求经过
网关
,判断请求的 Token 在
缓存
中是否存在,如果缓存中不存在该 Token,则提示用户
重新登录
。
springsecurity数据库的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于springsecurity数据库,保护你的应用程序安全:使用SpringSecurity数据库,在spring security3中启用用户的缓存功能后,如何去测试缓存已经发挥作用?,使用spring security框架打开页面怎么这么慢,单点登录JWT与Spring Security OAuth的信息别忘了在本站进行查找喔。