Spring Security是什么?
Spring Security is a powerful and highly customizable authentication and access-control framework. ————spring官网
显然而易见,它是一个可以帮我们实现登录认证、角色(资源)权限控制的框架,此外,它还提供了一些诸如CSRF攻击拦截的功能
登录认证
登录认证的演示将会做大概如下几个步骤:
配置spring security相关内容。
简单叙述用户角色权限。
代码配置。
代码用户逻辑编写。
应用
新建一个微服务article-auth
创建user表
CREATE TABLE `t_user` (
`id` BIGINT(20) NOT NULL COMMENT '用户id',
`username` VARCHAR(64) NOT NULL COMMENT '用户登录账号',
`password` VARCHAR(64) NOT NULL COMMENT '用户登录密码',
`fullname` VARCHAR(255) NOT NULL COMMENT '用户姓名',
`mobile` VARCHAR(11) DEFAULT NULL COMMENT '手机号',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT '用户表';
加入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
增加一个WebSecurityConfigurerAdapter的继承类,我们可以通过这个类配置如何验证用户,对那些路径进行验证,对请求加入哪些拦截器校验等
实际上,当我们没有任何配置的时候,Spring Security会帮我们自动拦截所有请求并跳转一个由该框架提供的默认登录界面,
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 {
}
WebSecurityConfigurerAdapter提供了几种配置。这里我配置一些简单的规则:除了/login 之外所有url进行认证,可认证用户名密码只有(admin,admin)。
配置我们的用户,这里需要我们自己实现一个UserDetailsService的实现类并重载它的loadUserByUsername方法。它的作用显而易见:给它一个username,它返回一个完整的User对象。
重写configure(HttpSecurity http)可以配置对那些路径进行验证
。
重写 configure(AuthenticationManagerBuilder auth)可以配置如何验证用户
。
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("/login")
.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());
}
}
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访问,成功!可以正常访问接口。
访问权限控制
之前我们介绍了登录认证的基本用法,接下来我们将介绍,基于用户、角色权限,如何实现对接口的访问控制。
开启权限认证,在Application头顶上配置@EnableGlobalMethodSecurity注解prePostEnabled为true,此开关不开,后面的访问控制尽皆无效。
@SpringBootApplication
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class AticleAuthApplication {
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication.run(AticleAuthApplication .class, args);
}
}
在控制方法上配置注解@PreAuthorize(“hasRole(‘ROLE_ADMIN’)”),代表拥有‘ROLE_ADMIN’角色才能请求该方法,ROLE_ADMIN角色我们已经在之前的UserDetails中赋予了admin用户。
注意:这里的角色系统中也需要我们自行设计,这里只是用默认的方便展示。
登录admin,并访问 ,访问成功!想看失败结果可以将UserDetails中赋予角色的代码去掉,会发现此时访问会出现403错误。