一、SpringSecurity简介
安全框架就是解决系统安全的框架。如果没有安全框架,我们需要手动的处理每个资源的访问控制,这是非常麻烦的。使用了安全框架,我们可以通过配置的方式实现对资源的访问限制。
Spring Security是一个高度自定义的安全框架。利用Spring IOC、DI和AOP的功能,为系统提供了声明式安全访问控制功能,减少了为系统安全而编写大量重复代码的工作。使用Spring Security的原因很多,但大部分都是发现了Java EE的Servlet规范或EJB规范中的安全功能缺乏典型的企业级应用场景,同时认识到他们在WAR或EAR级别无法移植。因此如果更换服务器环境,还有大量工作去重写配置应用程序。使用Spring Security解决了这些问题,也为你提供许多其他有用的、可定制的安全功能。应用程序的两个主要区域是认证和授权(访问控制)。这两点也是Spring Security重要的核心功能。认证是建立一个他声明的主体的过程,一个主体一般指用户,设备或者一些可以在你的应用程序中执行动作的其他系统,简单来说就是系统认为用户是否能登录。授权指确定一个主体是否允许在你的应用程序中执行一个动作的过程,简单来说就是系统判断用户是否有权限去执行某些操作。
二、Security初体验
首先导入相关依赖包
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
直接新建立一个Controller
@RestController
public class TestController {
@RequestMapping("/hello")
public String test(){
return "hello";
}
}
运行程序后可以在控制台看见一串密码
当我们访问/hello这个controller时,会弹出一个security中自动配置的一个登录页面
security中默认的用户名是user,密码则是上面控制台中的字符串,输入对应的默认用户名和密码,就可以成功跳转到页面。
三、自定义Security登录的用户名和密码
在实际开发中,登录名和密码是我们开发者自己定义的,那么如何在security中自定义我们的用户名和密码呢。
首先介绍一个security中的一个类,UserDetailsService。
在UserDetailsService中有一个方法叫loadUserByUsername,传入的参数则是我们在页面上输入的用户名。
先来看代码。
public class UserService implements UserDetailsService {
@Autowired
PasswordEncoder passwordEncoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
if(!"admin".equals(username)){
throw new UsernameNotFoundException("用户名不存在");
}
String password=passwordEncoder.encode("123");
return new User(username,password, AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
}
}
passwordEncoder是一个对密码进行加密的类,这里不过多介绍。
方法返回的是一个security中的User,注意要与开发中自定义的User类进行区分。
通过上述代码的配置,可以实现自定义的用户名和密码,分别是admin和123.
四、自定义登录页面
首先需要在配置类中继承WebSecurityConfigurerAdapter,在配置类中进行配置的修改。
相关代码如下:
@Override
protected void configure(HttpSecurity http) throws Exception {
//表单提交
http.formLogin()
//自定义登录页面
.loginPage("/login.html")
//登录接口
.loginProcessingUrl("/login");
//授权
http.authorizeRequests()
//放行login登录页面,这个页面不需要认证
.antMatchers("/login.html").permitAll()
//除上面的login登录页面之外,其他页面都要经过登录
.anyRequest().authenticated();
//关闭防火墙
http.csrf().disable();
}
自定义的login.html就是一个简单的表单,但是要注意,提交方式一定要选择post,否则无法进行提交
<form action="/login" method="post">
用户名:<input type="text" name="username">
密码:<input type="password" name="password">
<input type="submit" value="提交">
</form>
五、权限
//授权
http.authorizeRequests()
//放行login登录页面,这个页面不需要认证
.antMatchers("/login.html").permitAll()
//给页面授予权限
.antMatchers("/main.html").hasAuthority("admin")//只有admin权限的用户才可以进入这个页面
//除上面的login登录页面之外,其他页面都要经过登录
.anyRequest().authenticated();
六、角色
在使用角色来进行验证时,要先修改原本的service中的代码,其实就是在权限列表里加上角色的字段,这个字段固定要以“ROLE_”来开头
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
System.out.println("自定义登录逻辑");
if(!"admin".equals(username)){
throw new UsernameNotFoundException("用户名不存在");
}
String password=passwordEncoder.encode("123");
return new User(username,password, AuthorityUtils.commaSeparatedStringToAuthorityList("admin,ROLE_abc"));
}
//授权
http.authorizeRequests()
//放行login登录页面,这个页面不需要认证
.antMatchers("/login.html").permitAll()
//给页面授予权限
// .antMatchers("/main.html").hasAuthority("admin")
.antMatchers("/main.html").hasRole("abC")
//除上面的login登录页面之外,其他页面都要经过登录
.anyRequest().authenticated();