????????Spring Security是一种基于 Spring AOP 和 Servlet 过滤器的企业级安全框架,由 spring 官方推出,提供全面的安全性解决方案,它对软件系统中的认证、授权、加密等功能进行封装,并在Spring Boot 技术推出以后,配置方面做了很大的简化。
????????Spring Security 本质是一个过滤链条,其中有比较重要的三条过滤器:
? ? ? ? 1:FilterSecurityInterceptor:是一个方法级的权限过滤器,基本位于过滤器链的最底部。
? ? ? ? 2:ExceptionTranslationFilter:是个异常过滤器,用来处理在认证授权过程中抛出的异常。
? ? ? ? 3:UsernamePasswordAuthenticationFilter:对/login的post请求做拦截,校验表单中的用户名和密码。
? ? ? ? 过滤器加载流程:
? ? ? ? 使用SpringSecurity配置过滤器(DelegatingFilterProxy),在doFilter方法里使用初始化方法,得到一个叫FilterChainProxy的过滤器,在FilterChainProxy过滤器中得到所有的过滤器并加载到过滤链中,在SecurityFilterChain过滤器中调用getFilters方法完成加载。
? ? ? ? 实现Security需要用到两个比较重要的接口:
? ? ? ? 1、UserDetailsService接口:什么都没有配置的时候,登录账号和密码是由Sercurity定义生成,但当我们需要实际的账号和密码时,就需要通过自定义逻辑控制认证逻辑。
? ? ? ? 2、PasswordEncoder接口:数据加密接口,其中BCryptPasswordEncoder是Security官方推荐的密码解析器。表示验证从存储中获取的编码密码与编码后提交的原始密码是否匹配,如果密码匹配,则返回 true,否则返回 false。
? ? ? ? 准备工作(一)构建项目:
????????
?
?
? ? ? ? 下一步?finish后,创建一个简单的controller以及yal配置,完成访问测试:

server:
port: 8089
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/wanxi?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=UTF-8&useSSL=false
username: root
password: 19980801
? ? ? ? ?启动成功后会,访问配置的路径,会看到这样一个页面,此登录页面是security自带的,用户名是"user",密码在你启动时会给出(在下一张图展示)"e8ea2c58-6989-4895-bf3d-6208f0ac8c98"

?
? ? ? ? ?完成用户名及密码的输入后,便能成功访问到想要的效果:

? ? ? ? ?至此,项目创建完成。
? ? ? ? 1、创建至少2个controller,以便测试:
@RestController
public class SecurityController {
@RequestMapping("/hello")
public String hello() {
return "hello springboot !";
}
@RequestMapping("/user")
public String user() {
return "成功访问user资源。。。";
}
}
? ? ? ? 2、创建一个自定义的配置类,配置资源认证规则:
@Configuration
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void configure(HttpSecurity http) throws Exception {
// 第一步,当访问的是hello资源时不需要进行验证。
http.authorizeRequests()
.antMatchers("/hello").permitAll() // 放行指定的资源
.anyRequest().authenticated()
.and()
.formLogin();
}
}
? ? ? ? 配置完成后,再次访问时即可发现,访问hello资源,无需做额外操作,但是访问的不是hello资源时,则会给到一个登录页面,登录成功才能完成资源访问。
? ? ? ? 如果觉得每次需要复制密码登录麻烦,可以去yml里面配置登录用的用户名和密码:
spring:
security:
user:
name: wx
password: 123456
? ? ? ? 至此,就完成了Security两大部分之一的Authentication:认证。
? ? ? ? 3、接下来,为controller添加访问权限:
@RestController
public class SecurityController {
@RequestMapping("/hello")
public String hello() {
return "hello springboot !";
}
@PreAuthorize("hasAuthority('wx:user')")
@RequestMapping("/user")
public String user() {
return "成功访问user资源。。。";
}
@PreAuthorize("hasAuthority('wx:other')")
@RequestMapping("/other")
public String other() {
return "成功访问other资源。。。";
}
}
? ? ? ? 4、创建一个userEntity,并实现UserDetails接口:
public class UserEntity implements UserDetails {
private long id;
private String username;
private String password;
public void setAuthorities(Set<? extends GrantedAuthority> authorities) {
this.authorities = authorities;
}
private Set<? extends GrantedAuthority> authorities = new HashSet<>();
public UserEntity() {
}
public UserEntity(long id, String username, String password) {
this.id = id;
this.username = username;
this.password = password;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public void setName(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String getUsername() {
return this.username;
}
@Override
public String getPassword() {
return this.password;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return this.authorities;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
@Override
public String toString() {
return "UserEntity{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
? ? ? ? 5、创建一个permission实体类,并实现GrantedAuthority接口:
public class Permission implements GrantedAuthority {
private long id;
private String value;
@Override
public String getAuthority() {
return this.value;
}
public Permission() {
}
public Permission(long id, String value) {
this.id = id;
this.value = value;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
@Override
public String toString() {
return "Permission{" +
"id=" + id +
", value='" + value + '\'' +
'}';
}
}
????????6、创建myUserDetailsService(该名字最好和UserDetailsService区分开来),因为需要实现UserDetailsService接口:
@Service(value = "myUserDetailsService")
public class MyUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserEntity userEntity = new UserEntity();
userEntity.setName("wx");
// 这里密码必须使用加密后的密码,加密规则对应下文配置里的加密方法(我这里用的是BCrypt),password:123456
userEntity.setPassword("$2a$10$y/j0iaqkWkfgsa6OQtHgieT8Mg5xou0TLkiZ/8F8OzcuHBzSpukxm");
Permission permission = new Permission();
//添加权限允许访问规则
permission.setValue("wx:user");
Set<Permission> permissionSet = new HashSet<>();
permissionSet.add(permission);
userEntity.setAuthorities(permissionSet);
return userEntity;
}
}
? ? ? ? 7、修改?MySecurityConfig 配置类:
//@Configuration
//此注解是为controller里的方法添加约束,不至于可以随意访问
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
MyUserDetailsService myUserDetailsService;
@Override
protected void configure(HttpSecurity http) throws Exception {
// 第一步,当访问的是hello资源时不需要进行验证。
http.authorizeRequests()
.antMatchers("/hello").permitAll() // 放行指定的资源
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.userDetailsService(myUserDetailsService);
}
/**
* 为密码进行加密,这个得有
*/
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
? ? ? ? 8、启动入口函数、访问资源:
????????因为对hello资源放行了,因此可以直接访问资源 :

? ? ? ? 然后user资源添加了wx:user的权限,但是为当前用户开放了此权限,因此登录认证后可以访问资源(访问路径是:http:localhost/8089/user, login路径是自动跳转的):
?
? ? ? ? 接下来是加了wx:other权限的other资源,此资源配置了权限,但是并没有对当前用户开放,因此此用户登录后是无法访问该资源的:

? ? ? ? ?至此,登录认证和授权就算成功完成,以上代码亲测有效。
下一篇:Spring Security 加入 mybatis:http://t.csdn.cn/CmOAF???????
|