java web安全 架构师_Java架构师方案——Spring Security(一)快速入门(附完整项目代码)...

1. 导读

1.读完这篇文章你将免费获得一个SpringSecurity测试demo项目源码(可直接运行)。

2.你将学到如何快速创建一个SpringSecurity项目,实现简单的登入功能,很方便的集成到Springboot项目。

3.查看demo项目的运行测试效果,更具体地了解SpringSecurity功能。。

2. 快速认识Spring Security

什么是Spring Security

Spring Security 的前身是 Acegi Security ,是 Spring

项目组中用来提供安全认证服务的框架。它支持众多的认证技术,如LDAP、基于IEFT RFC 的标准、Form-based

authentication(简单用户接口)等等。概括就是:控制系统的登入拦截、用户登入认证、用户登入token的鉴权、系统api接口等资源的简单用户接口的权限控制。

简单地说,就是系统的登入逻辑和代码实现不用自己开发,使用Spring Security进行配置化开发就可以。

比较Spring Security登入业务与原生登入业务

原生登入逻辑开发流程有:

1)编写登入页面的form代码。

2)编写登入controller接口代码。

3)根据传入的用户名参数从数据库查询用户信息。

4)比较查询出来的密码数据与传入的密码,相同则登入通过,否则登入失败。

Spring Security登入逻辑开发流程:

1)编写登入页面的form代码。

2)Spring Security核心配置类开发。

3)实现UserDetailsService接口,在loadUserByUsername方法实现用户信息的加载。

为什么SpringSecurity登入业务开发工作量少

SpringSecurity开发工作少,是因为它对登入业务进行了非常完整的建模,登入业务的整个过程中,需要开发者自己开发的局部逻辑不多,其中包括:自定义登入页面,自定义用户数据获取来源(UserDetailsService实现类)

使用SpringSecurity来做系统的安全服务到底有多爽,下图代表了我此刻的内心。

cc45868a10c60318878e9a20ea2e82a3.png

快速入门

SpringBoot项目pom依赖

这个是集成SpringSecurity所需要依赖的jar包。

org.springframework.boot

spring-boot-starter-security

org.springframework.boot

spring-boot-starter-web

Springboot项目的pom文件中至少要包含上面两个依赖包。

SpringSecurity配置类

配置类要继承抽象类WebSecurityConfigurerAdapter,并使用注解@Configuration、@EnableGlobalMethodSecurity(prePostEnabled = true)修饰配置类。

/*** @Author: Galen

* @Date: 2019/3/27-14:43

* @Description: spring-security权限管理的核心配置

**/@Configuration

@EnableGlobalMethodSecurity(prePostEnabled= true)public class WebSecurityConfig extendsWebSecurityConfigurerAdapter {

@AutowiredprivateUserSecurityService userSecurityService;/*** @Author: jackdking

* @Description: 配置userDetails的数据源,密码加密格式

* @Date: 2020/5/21-5:24

* @Param: [auth]

*@return: void

**/@Overrideprotected void configure(AuthenticationManagerBuilder auth) throwsException {

auth.userDetailsService(userSecurityService)

.passwordEncoder(new BCryptPasswordEncoder());//实现自定义登录校验

}/*** @Author: Galen

* @Description: 配置放行的资源

* @Date: 2019/3/28-9:23

* @Param: [web]

*@return: void

**/@Overridepublic void configure(WebSecurity web) throwsException {

web.ignoring().antMatchers("/login.html", "/index.html","/css/**", "/static/**", "/login_p", "/favicon.ico")//给 swagger 放行;不需要权限能访问的资源

.antMatchers("/swagger-ui.html", "/swagger-resources/**", "/images/**", "/webjars/**", "/v2/api-docs", "/configuration/ui", "/configuration/security");

}/*** @Author: Galen

* @Description: 拦截配置

* @Date: 2019/4/4-10:44

* @Param: [http]

*@return: void

**/@Overrideprotected void configure(HttpSecurity http) throwsException {

http.authorizeRequests()//使其支持跨域

.requestMatchers(CorsUtils :: isPreFlightRequest).permitAll()//其他路径需要授权访问

.anyRequest().authenticated()

.and()

.formLogin().loginPage("/login_p")//设置登录页面,//奇怪的是 这个url并没有被访问到。

.loginProcessingUrl("/login")//自定义的登录接口,这个接口必须和你登入页面form的action地址一样。否则一直进入login_p页面:如果loginProcessingUrl不配置,默认是跟loginPage一样

.usernameParameter("username").passwordParameter("password")//告诉security form表单用户名和密码的参数表达式。

.failureHandler(new MyAuthenticationFailureHandler())//这个失败处理 跟 failureUrl 配置是互斥的。 两种只选择一种

.successHandler(new MyAuthenticationSuccessHandler())//跟defaultSuccessUrl互斥 ,这个支持返回json数据。如果不设置这个成功后的处理器,则会报错 999。//.defaultSuccessUrl("/index")//跟successHandler配置互斥,这个支持重定向到成功页面。 访问指定页面,用户未登入,跳转至登入页面,如果登入成功,跳转至用户访问指定页面,用户访问登入页面,默认的跳转页面//.failureUrl("/error_p")//重定向失败页面 跟 failureHandler 配置是互斥的。 两种只选择一种

.permitAll()

.and()

.csrf().disable();//关闭csrf

}

}

配置类覆盖configure(AuthenticationManagerBuilder auth),设置用户信息来源接口userDetailsService的实现类,以及用户密码的加密实现对象BCryptPasswordEncoder。

配置类覆盖configure(WebSecurity web),告知security框架哪些url不登入也能访问,例如一些css文件、js文件、登入页面等等。

配置类覆盖configure(HttpSecurity http),告知security登入业务的一些信息,例如登录页面、自定义的登录接口、form表单用户名和密码的参数表达式、登入失败或成功的handler类。

userDetailsService的开发

在这个实现类中,security框架允许开发者自定义用户信息的来源:可以是在代码里面,或是数据库、缓存服务器、第三方服务等。在这个demo项目里,我们运用的比较简单,直接写死在代码中,创建了SecuritySysUser对象返回给Security。

SecuritySysUser securityUser = newSecuritySysUser();

securityUser.setUsername(username);

securityUser.setPassword("$2a$10$4H1JSQxyrJlguu0/V4DnR.s2NBjE.k6rI6.W.1AFL0UEnR2IR2/5y");

securityUser.setEnabled(true);

List roles = new ArrayList<>();

SecuritySysRole role= newSecuritySysRole();

role.setNameCn("ROLE_ADMIN");

securityUser.setRoles(roles);if (securityUser == null) {throw new UsernameNotFoundException("用户名不对");

}

log.info("用户信息:{}", securityUser.toString());return securityUser;

到这,使用security框架来开发用户登入业务结束了,那我们来看看运行效果。

3. 运行Spring Security项目

本文的demo项目获取方式在文章底部查看。

右击项目文件com.jackdking.security.SpringSecurityApplication,选择Run As -> Java Application。

370a811a8059d2e9b207e59b70120850.png

输入用户名/密码:admin/admin,点击登入按钮,然后查看返回的登入json信息。

8d3b2f9c3671844bd7d2f294f253e462.png

登入成功返回的json数据是security框架的登入成功处理器返回的结果:successHandler(new MyAuthenticationSuccessHandler())。

@Overridepublic void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throwsIOException, ServletException {

response.setContentType("application/json;charset=utf-8");

RespBean respBean= RespBean.ok("【MyAuthenticationSuccessHandler】登录成功!", SecurityUserUtil.getCurrentUser());newGalenWebMvcWrite().writeToWeb(request,response, respBean);

System.out.println("【MyAuthenticationSuccessHandler】登录成功!");

}

输入错误的用户名和密码,返回的json信息,是错误处理器中的第一个异常错误类UsernameNotFoundException。

dce0641f4a16b86bf2c10400f478fddf.png

登入失败返回的json数据是security框架的登入失败处理器返回的结果:failureHandler(new MyAuthenticationFailureHandler())。

response.setContentType("application/json;charset=utf-8");

RespBean respBean;if (exception instanceof BadCredentialsException ||exceptioninstanceofUsernameNotFoundException) {

respBean= RespBean.error("账户名或者密码输入错误!");

}else if (exception instanceofLockedException) {

respBean= RespBean.error("账户被锁定,请联系管理员!");

}else if (exception instanceofCredentialsExpiredException) {

respBean= RespBean.error("密码过期,请联系管理员!");

}else if (exception instanceofAccountExpiredException) {

respBean= RespBean.error("账户过期,请联系管理员!");

}else if (exception instanceofDisabledException) {

respBean= RespBean.error("账户被禁用,请联系管理员!");

}else{

respBean= RespBean.error("登录失败!");

}

System.out.println("失败逻辑处理。");//response.setStatus(401);

new GalenWebMvcWrite().writeToWeb(request, response, respBean);

4. 如何正确看待web安全服务

作为架构师,当然希望系统能使用成熟的、功能特性丰富的安全服务框架,而security正是做好的选择。而且无论是从建设安全服务的人力、测试、运维、风险等成本角度考虑,security都是非常香的。

Spring Security安全服务框架的配置化开发也大大提高了整个团队的开发效率,如果系统单独自己做一个安全服务框架,未来团队成员交接成本也会非常的高,也会伴随着较大的风险成本。

查看更多 “Java架构师方案” 系列文章 以及 SpringBoot2.0学习示例

介绍

SpringBoot2.0-Jackdking 使用的各种示例,整合流行的中间件,此开源项目中的每个示例都是站在初学者角度,细心剖析技术实现细节,帮助初学者快速掌握 Spring Boot2.0 各组件的使用。

文章

完整的demo项目,请关注公众号“前沿科技bot“并发送"SEC-ONE"获取。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值