NoteBook / Spring Boot基础(6)

  1. Spring Security概念
  2. Spring Boot对Spring Security的支持
  3. 企业Spring Security操作

Spring Security是一个强大且高度可定制的身份验证和访问控制框架

  • Spring Security概念

为基于Spring的企业应用系统提供安全访问控制解决方案的安全框架

安全框架主要包括2个操作:

认证:确认用户可以访问当前系统

授权:确定用户在当前系统中是否能够执行某个操作,即用户所拥有的功能权限

Spring Security包括多个模块:

核心模块(spring-security-core.jar):任何使用Spring Security的应用程序都需要这个模块

基于annotation注解来完成Spring Security的功能


  • Spring Boot对Spring Security的支持

(1)Security适配器

在Spring Boot中配置Spring Security非常简单,创建一个自定义类继承WebSecurityConfigurerAdapter,并在该类中使用@EnableWebSecurity注解,就可以通过重写config方法来配置所需要的安全配置

WebSecurityConfigurerAdapter是Spring Security为Web应用提供的一个适配器,提供了2个方法:

configure(HttpSecurity httpSecurity):定义哪些URL需要被保护,定义当需要用户登录时,跳转到的登录页面

configureGlobal(AuthenticationManagerBuilder auth):用于创建用户和用户的角色

(2)用户认证

通过在configureGlobal(AuthenticationManagerBuilder auth)完成用户认证的

使用AuthenticationManagerBuilder的inMemoryAuthentication()方法可以添加用户,并给用户指定权限:

auth.inMemoryAuthentication().withUser("fkit").password("123456").roles("ADMIN","DBA");

Spring Security保存用户权限时,默认使用“ROLE_”,也就是说,“ADMIN”实际上是“ROLE_ADMIN”

(3)用户授权

通过configure(HttpSecurity http)完成用户授权的

HttpSecurity的authorizeRequests()方法有多个子节点,指定用户可以访问的多个URL模式

http.authorizeRequests():开始请求权限匹配

anyRequest().authenticated():其余所有的请求都需要认证(用户登录)之后才可以访问

HttpSecurity还可以设置登录的行为:

formLogin():开始设置登录操作

loginPage("/login"):设置登录页面的访问地址

usernameParameter("loginName").passwordParameter("password"):登录时接收传递的参数"loginName"的值作为用户名,接收传递的参数"password"的值作为密码

exceptionHandling().accessDeniedPage("/accessDenied"):指定异常处理页面

(4)Spring Security核心类

Authentication:用户认证信息,Authentication对象

SecurityContextHolder:保存SecurityContext,含有当前所访问系统的用户的详细信息,获取当前登录用户的用户名:

String username = SecurityContextHolder.getContext().getAuthentication().getName();

UserDetails:定义了一些可以获取用户名、密码、权限等与认证相关的信息的方法,UserDetails是通过UserDetailsService的loadUserByUsername()方法进行加载的

UserDetailsService:Spring Security通过UserDetailsService的loadUserByUsername()方法获取对应的UserDetails进行认证,认证通过后会将该UserDetails赋给认证通过的Authentication的principal,然后再把该Authentication存入SecurityContext,之后如果需要使用用户信息,可以通过SecurityContextHolder获取存放在SecurityContext中的Authentication的principal

GrantedAuthority:Authentication的getAuthorities()可以返回当前Authentication对象拥有的权限,返回值是一个GrantedAuthority类型的数组,通常通过UserDetailsService进行加载,然后赋予UserDetails的

DaoAuthenticationProvider:默认使用DaoAuthenticationProvider实现AuthenticationProvider接口,专门进行用户认证的处理

PasswordEncoder:对密码加密,BCryptPasswordEncoder是较好的选择,可以由客户端指定加密的强度

(5)Spring Security的验证机制

Spring Security大体上是由一堆Filter实现的,Filter会在Spring MVC前拦截请求,Filter包括登出Filter、用户名密码验证Filter之类,Filter再交由其他组件完成细分的功能

(6)Spring Boot的支持

Spring Boot针对Spring Security提供了自动配置的功能

通过org.springframework.boot.autoconfigure.security包对Spring Security提供了自动配置的支持,主要通过SecurityAutoConfiguration和SecurityProperties两个类来完成

SecurityProperties类使用以“security”为前缀的属性配置Spring Security相关的配置

当需要自己扩展时,只需要自定义类继承WebSecurityConfigurerAdapter,无须再使用@EnableWebSecurity注解

Spring Boot自动注册Security的过滤器

Spring Boot Security示例:

1、修改pom.xml文件,引入依赖spring-boot-starter-security

2、html页面

3、Spring Security认证处理类:AppSecurityConfigurer.java,用于用户认证和授权操作

@Configuration

public class AppSecurityConfigurer extends WebSecurityConfigurerAdapter {……}

密码存储格式为:{id}encodedPassword,id是一个标识符,用于查找是哪个PasswordEncoder,encodedPassword是经过加密之后的密码,设置密码的示例代码如下:

auth.inMemoryAuthentication().withUser("fkit").password("{noop}123456").roles("USER");

Spring Security还提供了密码编辑器接口PasswordEncoder,自定义密码编辑器类必须实现PasswordEncoder接口

注入认证成功处理类:

AppAuthenticationSuccessHandler appAuthenticationSuccessHandler;

.successHandler(appAuthenticationSuccessHandler);

4、创建认证成功处理类:AppAuthenticationSuccessHandler.java,用于处理登录成功之后的操作

@Component

public class AppAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {......}

通过RedirectStrategy对象负责所有重定向任务

private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();

重写handle方法,方法中通过RedirectStrategy对象重定向到指定的URL

从Authentication对象中提取当前登录用户的角色,并根据其角色返回适当的URL

redirectStrategy.sendRedirect(request,response,targetUrl);

5、转发请求的控制器

@Controller

public class AppController {……}

注销:new SecurityContextLogoutHandler().logout(request,response,auth);

通过getUsername()方法获得当前认证用户的用户名,通过getAuthority()方法获得当前认证用户的权限,并设置到Model中

6、测试应用

Spring Boot项目启动后,就调用了AppSecurityConfigurer.java


  • 企业Spring Security操作

操作企业数据库主流的方式有JPA、MyBatis、JDBC,通过验证登录名loginName和密码password进行认证并授权,同时密码使用加密处理,避免将密码明文存储到数据库

(1)基于JPA的Spring Boot Security操作

创建用户类和角色类

FKRole.java:
@Column(name="id")
private Long id;
@Column(name="authority")
private String authority;

FKUser.java:
@ManyToMany(cascade = {CascadeType.REFRESH},fetch = FetchType.EAGER)
@JoinTable(name="tb_user_role",joinColumns={@JoinColumn(name="user_id")},inverseJoinColumns={@JoinColumn(name="role_id")})
private List<FKRole> roles;

用户和权限的关系是多对多关系

创建数据库访问接口:UserRepository.java

创建自定义服务类:UserService.java

需要实现UserDetailsService接口,因为在Spring Security中配置的相关参数需要是UserDetailsService类型的数据

public class UserService implements UserDetailsService {……}

重写UserDetailsService接口中的loadUserByUsername方法,通过该方法查询对应的用户,返回对象UserDetails是Spring Security的一个核心接口

其中调用持久层接口findByLoginName方法查找用户,通过JPA进行数据库验证

FKUser fkuser = userRepository.findByLoginName(username);

最后将获得的用户名、密码和权限保存到org.springframework.security.core.userdetails.User类中并返回

创建Spring Security的认证处理类AppSecurityConfigurer.java

依赖注入用户认证接口

private AuthenticationProvider authenticationProvider;

DaoAuthenticationProvider是Spring Security提供的AuthenticationProvider实现

通过重写configureGlobal方法添加自定义的认证方式

@Override
protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(authenticationProvider);
}

@Bean
public Authentication authentication() 
{
    ……
    provider.setUserDetailsService(userService);
    provider.setPasswordEncoder(passwordEncoder);
    returen provider;    
}

.anyRequest().authenticated()表示其他的请求都必须要有权限认证

使用AuthenticationManagerBuilder的authenticationProvider()方法进行认证,在authenticationProvider()方法中调用setUserDetailsService()方法传入自定义的UserService对象进行用户登录认证,认证通过后会将UserDetails赋给认证通过的Authentication的principal,然后再把该Authentication存入SecurityContext

在authenticationProvider()方法中调用setPasswordEncoder()方法传入Spring Security提供的BCryptPasswordEncoder对象进行密码加密验证(对输入的密码加密,再比对此加密后的密码与数据库中密码是否相等

(2)基于MyBatis的Spring Boot Security操作

持久层使用的是MyBatis框架

Spring Boot会自动加载spring.datasource.*相关配置,数据源就会自动注入sqlSessionFactory,sqlSessionFactory会自动注入Mapper

创建数据访问接口UserMapper.java,和JPA测试中的UserRepository作用完全一致,区别在于JPA自动生成SQL语句,而MyBatis需要开发者自动提供SQL语句

修改App类:

@MapperScan("org.fkit.securitymybatistest.mapper")      //扫描数据访问层接口的包名

作用是让Spring能够扫描该包下面所有MyBatis的Mapper类,还有一种方式是直接在Mapper类中添加注解@Mapper

(3)基于JDBC的Spring Boot Security操作

持久层使用JDBC操作数据库

创建数据访问接口UserRepository.java,注入JdbcTemplate:

@Autowired

private JdbcTemplate jdbcTemplate;

//根据loginName查询用户
FKUser fkUser = jdbcTemplate.queryForObject(sql,new Object[]{loginName},new RowMapper<FKUser>(){
    @Override
    public FKUser mapRow(ResultSet rs,int rowNum) throws SQLException{……}
}
);

//根据用户id查询用户权限
List<Map<String,Object>> result = jdbcTemplate.queryForList("……",new Object[]{fkUser.getid()});

JDBC需要开发者自己提供SQL语句并处理结果集,其他的工作都交给JdbcTemplate对象完成

JPA和MyBatis的Spring Security操作是现代开发的主流

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值