赞
踩
欢迎来嫖从零开始SpringCloud Alibaba电商系列:
Spring Security is a powerful and highly customizable authentication and access-control framework. ————spring官网
显然而易见,它是一个可以帮我们实现登录认证、角色(资源)权限控制的框架,此外,它还提供了一些诸如CSRF攻击拦截的功能,有兴趣的同学可以查一下。
有的同学可能疑惑,权限认证这种东西我写个select+ifelse不就完了吗?用它干啥?
嗯,看完,然后,真香……
登录认证的演示将会做大概如下几个步骤:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
如何验证用户
,对那些路径进行验证
,对请求加入哪些拦截器校验
等。package com.lele.mall.config;/* * com.lele.mall.config * @author: lele * @date: 2020-04-18 */ import org.springframework.beans.factory.annotation.Configurable; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; @Configurable @EnableWebSecurity public class SimpleSecurityConfig extends WebSecurityConfigurerAdapter { }
3. WebSecurityConfigurerAdapter提供了几种配置。这里我配置一些简单的规则:除了/test之外所有url进行认证,可认证用户名密码只有(admin,admin)。
重写configure(HttpSecurity http)可以配置`对那些路径进行验证`。
重写 configure(AuthenticationManagerBuilder auth)可以配置`如何验证用户`。
然后尝试访问localhost:8081/order/apply,结果直接跳转到登录页面:
4. 配置我们的用户,我在这里写了死数据,正常项目我们一般配合数据库来做。
值得一提,这里需要我们自己实现一个UserDetailsService的实现类并重载它的loadUserByUsername方法。它的作用显而易见:给它一个username,它返回一个完整的User对象。
修改后的SimpleSecurityConfig如下:
package com.lele.mall.config;/* * com.lele.mall.config * @author: lele * @date: 2020-04-18 */ import com.lele.mall.MyUserDetailsService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Configurable; import org.springframework.context.annotation.Bean; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.NoOpPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; @Configurable @EnableWebSecurity public class SimpleSecurityConfig extends WebSecurityConfigurerAdapter { // 引入自定义userDetails @Autowired MyUserDetailsService myUserDetailsService; @Bean public PasswordEncoder passwordEncoder(){ //return new BCryptPasswordEncoder(); return NoOpPasswordEncoder.getInstance(); // 不对密码进行加密 } /** * 通过http对象配置具体的认证规则、路由权限规则 * 这里用http对象代替xm配置,注意这里每个and()之间的配置都相当于原来xml中一个标签包含的配置。 * @param http * @throws Exception */ @Override protected void configure(HttpSecurity http) throws Exception { http .formLogin()// 使用默认的表单登录 .permitAll() .and() .authorizeRequests() .antMatchers("/test") .permitAll() .anyRequest() // 捕获所有路径 .authenticated(); } /** * 用户认证规则,即用户传递何种信息才可以登录 * myUserDetailsService.loadUserByUsername 通过传入username,返回我们的user数据, * passwordEncoder 会对user数据中的password进行BCrypt算法加密。 * @param auth * @throws Exception */ @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(myUserDetailsService); //.passwordEncoder(passwordEncoder()); } }
新增MyUserDetail如下:
package com.lele.mall;/* * com.lele.mall * @author: lele * @date: 2020-04-19 */ import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.User; 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 java.util.ArrayList; import java.util.List; @Service public class MyUserDetailsService implements UserDetailsService { /** * 这里应该实现自定义认证逻辑:通过username查库找到user * @param s * @return 返回一个Srping Security规定的UserDetails,包含密码和用户权限 * @throws UsernameNotFoundException */ @Override public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException { if( !s.equals("admin") ) throw new UsernameNotFoundException(s + "用户名不存在"); // 资源权限,之后可以通过这里赋予的权限控制接口访问。 List<GrantedAuthority> roles = new ArrayList<GrantedAuthority>(); roles.add(new SimpleGrantedAuthority( "ROLE_ADMIN")); return new User(s,"admin",roles); } }
admin,pass
访问,失败。第二次使用admin,admin
访问,成功!可以正常访问接口。以上我们介绍了一个spring security最简单的一个例子,之后在我们即将构建的电商系统中,还会介绍如何配置一个自己的登录页面、如何对密码加密解密以及CSRF攻击拦截等功能。
之前我们介绍了登录认证的基本用法,接下来我们将介绍,基于用户、角色权限,如何实现对接口的访问控制。
@SpringBootApplication
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MallApplication {
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication.run(MallApplication.class, args);
}
}
在order/apply方法脑袋上配置注解@PreAuthorize(“hasRole(‘ROLE_ADMIN’)”),代表拥有‘ROLE_ADMIN’角色才能请求该方法,ROLE_ADMIN角色我们已经在之前的UserDetails中赋予了admin用户。
注意:这里的角色系统中也需要我们自行设计,这里只是用默认的方便展示。
登录admin,并访问 /order/apply,访问成功!想看失败结果的同学可以将UserDetails中赋予角色的代码去掉,会发现此时访问会出现403错误。
https://github.com/flyChineseBoy//lel-mall-learning/tree/master/mall07
下一节,我们继续来看Spring Security,它在分布式场景下,是如何保证各个子系统间登录信息互通的。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。