Spring Security(1)——基于内存认证信息(附完整项目代码)
1. 快速体验Security框架
Springboot项目集成Spring Security安全框架,需要做很多的工作,其中最重要的一个工作是实现Security框架的UserDetail接口,将数据库中的用户信息(用户名、密码)和权限信息加载出来。意味着我们要做DAO层、Service层、建表等工作。
这些工作对于想快速体验Security集成效果的读者来说就显得非常繁重了,因为首先你得有个数据库。
现在,本项目基于内存认证信息的demo就供读者直接运行,查看登入效果。读者下载完整demo项目直接启动,浏览器访问:http://localhost:8080
读者会看到下面的页面内容。
没有登入,则会先跳转到login页面。判断是否满足权限,再决定页面跳转,
2. 配置pom依赖
<dependencies>
<!-- springboot依赖,springboot项目都需要配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- spring security依赖,springBoot集成security框架pom依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- 下面两个依赖 是thymleaf模板依赖,本项目页面模板 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
<scope></scope>
</dependency>
</dependencies>
3. 基于内存认证的UserDetail
两种方式:用户信息放入内存
第一种
@EnableWebSecurity注解启动Spring Securiy,并使用Security框架自带的UserDetail实现类:org.springframework.security.provisioning.InMemoryUserDetailsManager。
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private AccessDeniedHandler accessDeniedHandler;
@Bean
@Override
protected UserDetailsService userDetailsService() {
//直接建两个用户存在内存中,生产环境可以从数据库中读取,对应管理器JdbcUserDetailsManager
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
// 创建两个用户
//通过密码的前缀区分编码方式,推荐,这种加密方式很好的利用了委托者模式,使得程序可以使用多种加密方式,并且会自动
//根据前缀找到对应的密码编译器处理。
manager.createUser(User.withUsername("guest").password("{bcrypt}" +
new BCryptPasswordEncoder().encode("111111")).roles("USER").build());
manager.createUser(User.withUsername("root").password("{sha256}" +
new StandardPasswordEncoder().encode("666666"))
.roles("ADMIN", "USER").build());
return manager;
}
......
}
第二种
基于内存认证,还有一种方式将用户信息、权限信息注入到security框架中:覆盖实现方法configure(AuthenticationManagerBuilder auth),具体如下,这时候,覆盖方法userDetailsService()是是小的,即root、guest用户信息失效。
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// TODO Auto-generated method stub
// super.configure(auth);
//userdetail实现类bean也可以在这里注入到security中,
// auth.userDetailsService(userDetailsService());
//通过两种方式 用户认证信息放入到security中。
// auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder()).withUser("jack").password("{bcrypt}" +new BCryptPasswordEncoder().encode("88888888")).roles("USER");
// auth.userDetailsService(userDetailsService());//覆盖了configure方法,那么覆盖userDetailsService()方法就失效了,因此root和guest都会失效,因此这里需要将UserDetail实现类bean注入到框架中。
auth.inMemoryAuthentication().withUser(User.withUsername("jack").password("{bcrypt}" +new BCryptPasswordEncoder().encode("88888888")).roles("USER"));
}
4. security配置
系统资源访问权限配置
antMatchers("/css/", "/js/", "/fonts/**").permitAll()
配置静态资源不用任何权限即可访问。
.antMatchers("/admin/**").hasAnyRole("ADMIN") // 满足该条件下的路由需要ROLE_ADMIN的角色
配置访问该path的资源需要用户认证且权限为“ADMIN”。
.anyRequest().authenticated()
其他未配置的资源访问都需要登入认证。
.formLogin().loginPage("/login").permitAll()
配置登入页面路径,且无需认证即可访问
logout().permitAll()
配置登出无需认证即可访问
exceptionHandling().accessDeniedHandler(accessDeniedHandler)
配置错误处理机制handler
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:on
http.authorizeRequests()
.antMatchers("/css/**", "/js/**", "/fonts/**").permitAll() // 允许访问资源
.antMatchers("/", "/home", "/about", "/login").permitAll() //允许访问这三个路由
.antMatchers("/admin/**").hasAnyRole("ADMIN") // 满足该条件下的路由需要ROLE_ADMIN的角色
.antMatchers("/user/**").hasAnyRole("USER") // 满足该条件下的路由需要ROLE_USER的角色
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll()
.and()
.exceptionHandling().accessDeniedHandler(accessDeniedHandler).and()
.csrf().disable();
// @formatter:off
}
5. 密码加密
两种配置加密方式
通过AuthenticationManagerBuilder指定和通过@Bean注入指定PasswordEncoder
auth.inMemoryAuthentication().withUser(User.withUsername("jack").password("{bcrypt}" +new BCryptPasswordEncoder().encode("88888888")).roles("USER"));
auth.inMemoryAuthentication().withUser(User.withUsername("king").password(passwordEncoder().encode("88888888")).roles("USER"));
对于两种方式,前者是将加密方式写死在编码逻辑中,而后者是通过一个抽象方法维护,这样的方式能通过模板方法模式更好地维护加密方式。
6. 登入逻辑测试
测试效果我就不展示了,大家可以clone demo项目运行后自行操作。先看看king用户登入的效果图。
访问Admin
访问User
完整的demo项目,请关注公众号“前沿科技bot“并发送"SEC-TWO"获取。
- 本文标签: Spring Boot Spring Security
- 版权声明: 本站原创文章,于2020年12月29日由空白发布,转载请注明出处