文章目录
Web 权限方案
一、认证 - 登陆
设置登陆的用户名和密码:
- 通过配置文件
- 通过配置类
- 自定义编写实现类
方式一:编写配置文件 - application.properties
通过配置文件修改后,我们再次启动项目,进行测试:
如上图所示,显然此时我们登陆的用户名为admin、密码为123456,并且注意在控制台中原先默认生成的一串加密的随机密码也没有了。
返回顶部
方式二:编写配置类
配置登陆用户信息方式二:配置类
1.添加注解 @Configuration
2.继承 WebSecurityConfigurerAdapter 接口
3.重写方法:configure(AuthenticationManagerBuilder auth)
编写好配置类后我们重启项目进行测试,结果发现报错了:There is no PasswordEncoder mapped for the id "null"
主要是需要对密码进行加密操作,定义的 password()
方法返回一个 BCryptPasswordEncoder对象,对上面的密码进行加密。这样就解决了该问题。
@Bean
PasswordEncoder password() {
return new BCryptPasswordEncoder();
}
测试:
完整代码:
package com.zyx.securitydemo1.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
* @author 35192
* @date 2021-07-25 15:26
*
* 配置登陆用户信息方式二:配置类
* 1.添加注解 @Configuration
* 2.继承 WebSecurityConfigurerAdapter 接口
* 3.重写方法:configure(AuthenticationManagerBuilder auth)
*/
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
/**
* AuthenticationManagerBuilder用于创建 AuthenticationManager
* 允许在内存中轻松构建身份验证、LDAP 身份验证、基于 JDBC 的身份验证、添加 UserDetailsService 和添加 AuthenticationProvider。
* @param auth
* @throws Exception
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// 密码加密处理
BCryptPasswordEncoder bcpe = new BCryptPasswordEncoder();
String pwd = bcpe.encode("123456");
// 构建登陆用户名、密码、身份
auth.inMemoryAuthentication().withUser("zyx").password(pwd).roles("管理员");
}
/**
* 返回一个 BCryptPasswordEncoder,对上面的密码进行加密
* @return
*/
@Bean
PasswordEncoder password() {
return new BCryptPasswordEncoder();
}
}
返回顶部
方式三:自定义编写实现类 - 数据库
以上两种方式,在项目启动的时候都会自动去查询,如果都没有进行配置就会按照默认的。一般我们数据存储在数据库中,并且通过以上两种方式并不太便于实现从数据库中查询用户进行认证,那么我们就需要使用到自定义的方式来进行操作了。
第一步:修改配置类,设置使用哪个userDetailsService实现类
package com.zyx.securitydemo1.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.PasswordEncoder;
/**
* @author 35192
* @date 2021-07-25 16:11
*/
@Configuration
public class SelfDFSecurityConfig extends WebSecurityConfigurerAdapter {
// 修改一:注入UserDetailsService对象
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// 修改二:指明哪个自定义的实现类并进行加密配置
auth.userDetailsService(userDetailsService) // 指定自定义的UserDetailsService实现类
.passwordEncoder(password()); // 加密配置
}
/**
* 返回一个 BCryptPasswordEncoder,对上面的密码进行加密
* @return
*/
@Bean
PasswordEncoder password() {
return new BCryptPasswordEncoder();
}
}
第二步:编写实现类(数据库操作),返回User对象
package com.zyx.securitydemo1.service;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
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.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @author 35192
* @date 2021-07-25 16:24
*/
@Service("userDetailsService") // 注意此处名称与配置类中的注入对象名称的一致性!!!
public class MyUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 权限集合
List<GrantedAuthority> authorities =
AuthorityUtils.commaSeparatedStringToAuthorityList("role");
// 返回User对象
return new User("zzz",new BCryptPasswordEncoder().encode("123456"),authorities);
}
}
测试:
总结
返回顶部
二、实现数据库认证完成用户登陆
2.1 添加pom.xml依赖配置
<!--mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--lombok 用来简化实体类-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
返回顶部
2.2 配置数据库信息
数据库配置:
# mysql 数据库连接
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/security?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false&allowMultiQueries=true
spring.datasource.username=root
spring.datasource.password=123456
数据表:
返回顶部
2.3 创建数据库表对应实体类
package com.zyx.securitydemo1.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
/**
* @author 35192
* @date 2021-07-25 17:19
*/
@Data
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class Users {
private Integer id;
private String username;
private String password;
}
返回顶部
2.4 创建 UsersMapper
package com.zyx.securitydemo1.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.zyx.securitydemo1.entity.Users;
import org.springframework.stereotype.Repository;
/**
* @author 35192
* @date 2021-07-25 17:21
*/
@Repository
public interface UsersMapper extends BaseMapper<Users> {
}
返回顶部
2.5 自定义编写实现类进行认证
package com.zyx.securitydemo1.service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zyx.securitydemo1.entity.Users;
import com.zyx.securitydemo1.mapper.UsersMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
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.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @author 35192
* @date 2021-07-25 16:24
*/
@Service("userDetailsService")
public class MyUserDetailsService implements UserDetailsService {
@Autowired
private UsersMapper usersMapper;
/**
* @param username 获取的就是登陆页表单中的用户名值
* @return
* @throws UsernameNotFoundException
*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 调用usersMapper方法根据用户名查询数据库
QueryWrapper<Users> wrapper = new QueryWrapper<>();
// where username=?
wrapper.eq("username",username);
// 获取查询结果
Users user = usersMapper.selectOne(wrapper);
// 判断
if (user==null){
// 数据库未查到,认证失败
throw new UsernameNotFoundException("用户名不存在!");
} else {
// 权限集合
List<GrantedAuthority> authorities =
AuthorityUtils.commaSeparatedStringToAuthorityList("role");
// 从数据库中返回的user对象中获取用户名、密码封装到User对象返回
return new User(user.getUsername(), new BCryptPasswordEncoder().encode(user.getPassword()), authorities);
}
}
}
返回顶部
2.6 编写配置类
package com.zyx.securitydemo1.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.PasswordEncoder;
/**
* @author 35192
* @date 2021-07-25 16:11
*/
@Configuration
public class SelfDFSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService) // 指定自定义的UserDetailsService实现类
.passwordEncoder(password()); // 加密配置
}
/**
* 返回一个 BCryptPasswordEncoder,对上面的密码进行加密
* @return
*/
@Bean
PasswordEncoder password() {
return new BCryptPasswordEncoder();
}
}
返回顶部
2.7 测试
我们输入错误的用户名进行debug测试,不断的往下运行,最终发现user为null。
第二次,我们输入正确的用户名进行debug测试,不断的往下运行,最终发现user查到了内容。
经过和数据库的表进行比对,发现以上两种结果均正确。
总结
返回顶部
三、自定义用户登录界面
3.1 引入登陆界面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/user/login" method="post">
用户名:<input type="text" name="username"/>
<br/>
密码:<input type="text" name="password"/>
<br/>
<input type="submit" value="login"/>
</form>
</body>
</html>
注意:页面提交方式必须为 post 请求,所以上面的页面不能使用,用户名,密码必须为 username,password
原因: 在执行登录的时候会走一个过滤器 UsernamePasswordAuthenticationFilter
如果修改配置可以调用 usernameParameter()和 passwordParameter()方法。
返回顶部
3.2 配置登陆认证、成功跳转等指定路径
- 重写
configure(HttpSecurity http)
方法
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin() // 自定义登陆表单
.loginPage("/login.html") // 登陆页面设置
.loginProcessingUrl("/user/login") // 登陆访问路径
.defaultSuccessUrl("/test/index").permitAll() // 登陆成功后,跳转的路径
.and().authorizeRequests()
.antMatchers("/", "/test/hello", "/user/login").permitAll() // 指定哪些路径可以直接访问,不需认证
.anyRequest().authenticated() // 映射任何请求,指定任何经过身份验证的用户都允许使用 URL
.and().csrf().disable(); // 关闭csrf防护
}
@GetMapping("index")
public String index(){
return "hello index";
}
返回顶部
3.3 测试
- 直接访问
/test/hello
路径,可以直接访问,无需认证!
- 直接访问
/test/index
路径,不可以直接访问,需要进行认证,并且由于我们配置了默认的主界面,所以跳转到自定义的 login.html
登陆页面
- 输入用户名、密码后提交到
/user/login
,可以直接访问,根据提交的username、password信息,MyUserDetailsService
中的loadUserByUsername()
获取到username值,然后到数据库中进行查询判断。查到结果即代表认证成功,触发 defaultSuccessUrl("/test/index").permitAll()
跳转页面显示信息。
总结
返回顶部
四、基于角色或权限进行访问控制
4.1 hasAuthority 方法
- 如果当前的主体具有指定的权限,则返回 true,否则返回 false
- 修改配置类:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin() // 自定义登陆表单
.loginPage("/login.html") // 登陆页面设置
.loginProcessingUrl("/user/login") // 登陆访问路径
.defaultSuccessUrl("/test/index").permitAll() // 登陆成功后,跳转的路径
.and().authorizeRequests()
// 指定哪些路径可以直接访问,不需认证
.antMatchers("/", "/test/hello", "/user/login").permitAll()
// 当前登录用户,只有具有admin权限才可以访问这个路径
.antMatchers("/test/index").hasAuthority("admin")
.anyRequest().authenticated() // 映射任何请求,指定任何经过身份验证的用户都允许使用 URL
.and().csrf().disable(); // 关闭csrf防护
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 调用usersMapper方法根据用户名查询数据库
QueryWrapper<Users> wrapper = new QueryWrapper<>();
// where username=?
wrapper.eq("username",username);
// 获取查询结果
Users user = usersMapper.selectOne(wrapper);
// 判断
if (user==null){
// 数据库未查到,认证失败
throw new UsernameNotFoundException("用户名不存在!");
} else {
// 权限集合 --- 授予登陆主体权限
List<GrantedAuthority> authorities =
AuthorityUtils.commaSeparatedStringToAuthorityList("admin");
// 从数据库中返回的user对象中获取用户名、密码封装到User对象返回
return new User(user.getUsername(), new BCryptPasswordEncoder().encode(user.getPassword()), authorities);
}
}
- 测试
- 当我们授予登陆主体的权限与指定访问路径所需的权限
一致
时,只要登陆成功,便可以访问到指定页面;但是当我们授予登陆主体的权限与指定访问路径所需的权限不一致
时,即使登陆用户、密码全正确,也是访问不到指定页面的。
返回顶部
4.2 hasAnyAuthority 方法
- 如果当前的主体有任何提供的角色(给定的作为一个逗号分隔的字符串列表)的话,返回 true。
- **按照hasAuthority(),我们赋予主体权限只有admin,但是请求路径需要admin,manager的时候,就会出现无法访问的问题。因为请求的路径需要同时具有admin,manager权限才可以。那么当我们想要表现出只要具有权限就可以访问时,可以使用hasAnyAuthority ()。 **
- 修改配置类:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin() // 自定义登陆表单
.loginPage("/login.html") // 登陆页面设置
.loginProcessingUrl("/user/login") // 登陆访问路径
.defaultSuccessUrl("/test/index").permitAll() // 登陆成功后,跳转的路径
.and().authorizeRequests()
// 指定哪些路径可以直接访问,不需认证
.antMatchers("/", "/test/hello", "/user/login").permitAll()
// 当前登录用户,只有具有admin权限才可以访问这个路径
//.antMatchers("/test/index").hasAuthority("admin")
//.antMatchers("/test/index").hasAuthority("admin,manager")
// 当前登陆用户,只要具有admin、manager权限中的任何一个就可以访问这个路径
.antMatchers("/test/index").hasAnyAuthority("admin,manager")
.anyRequest().authenticated() // 映射任何请求,指定任何经过身份验证的用户都允许使用 URL
.and().csrf().disable(); // 关闭csrf防护
}
// 权限集合 --- 授予登陆主体权限
List<GrantedAuthority> authorities =
AuthorityUtils.commaSeparatedStringToAuthorityList("admin");
- 测试
返回顶部
4.3 hasRole 方法
- 如果用户具备给定角色就允许访问,否则出现 403。 如果当前主体具有指定的角色,则返回 true。
- 底层源码:
- 给当前用户添加角色 “ROLE_…”
// 权限集合
List<GrantedAuthority> authorities =
AuthorityUtils.commaSeparatedStringToAuthorityList("admin,ROLE_sale");
- 注意配置文件中不需要添加”ROLE_“,因为上述的底层代码会自动添加与之进行匹配。
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin() // 自定义登陆表单
.loginPage("/login.html") // 登陆页面设置
.loginProcessingUrl("/user/login") // 登陆访问路径
.defaultSuccessUrl("/test/index").permitAll() // 登陆成功后,跳转的路径
.and().authorizeRequests()
// 指定哪些路径可以直接访问,不需认证
.antMatchers("/", "/test/hello", "/user/login").permitAll()
// 3.hasRole() 当前登录用户,只有具有role角色才可以访问这个路径
.antMatchers("/test/index").hasRole("sale") // ROLE_sale
.anyRequest().authenticated() // 映射任何请求,指定任何经过身份验证的用户都允许使用 URL
.and().csrf().disable(); // 关闭csrf防护
}
- 测试
返回顶部
4.4 hasAnyRole 方法
- 表示用户具备任何一个条件都可以访问。
- 给用户添加角色:
// 权限集合
List<GrantedAuthority> authorities =
AuthorityUtils.commaSeparatedStringToAuthorityList("admin,ROLE_sale");
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin() // 自定义登陆表单
.loginPage("/login.html") // 登陆页面设置
.loginProcessingUrl("/user/login") // 登陆访问路径
.defaultSuccessUrl("/test/index").permitAll() // 登陆成功后,跳转的路径
.and().authorizeRequests()
// 指定哪些路径可以直接访问,不需认证
.antMatchers("/", "/test/hello", "/user/login").permitAll()
// 3.hasRole() 当前登录用户,只有具有role角色才可以访问这个路径
//.antMatchers("/test/index").hasRole("sale") // ROLE_sale
// 4.hasAnyRole() 当前登录用户只要具有sale、customer角色中任何一个就可以访问这个路径
.antMatchers("/test/index").hasAnyRole("sale,customer") // ROLE_sale、ROLE_customer
.anyRequest().authenticated() // 映射任何请求,指定任何经过身份验证的用户都允许使用 URL
.and().csrf().disable(); // 关闭csrf防护
}
- 测试
总结
返回顶部
五、自定义403页面
5.1 修改访问配置类
http.exceptionHandling().accessDeniedPage("/403.html");
返回顶部
5.2 测试
总结
返回顶部
六、认证授权注解使用
6.1 @Secured
- 判断是否具有角色,另外需要注意的是这里匹配的字符串需要添加前缀“
ROLE_
“。 - 1.使用注解先要开启注解功能!
@EnableGlobalMethodSecurity(securedEnabled=true)
package com.zyx.securitydemo1;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
@SpringBootApplication()
@MapperScan("com.zyx.securitydemo1.mapper")
// 使用注解先要开启注解功能!
@EnableGlobalMethodSecurity(securedEnabled=true)
public class Securitydemo1Application {
public static void main(String[] args) {
SpringApplication.run(Securitydemo1Application.class, args);
}
}
@GetMapping("/testSecured")
@ResponseBody
@Secured({"ROLE_sale","ROLE_admin"})
public String wrong(){
return "hello test_Secured";
}
// 权限集合
List<GrantedAuthority> authorities =
AuthorityUtils.commaSeparatedStringToAuthorityList("admin,ROLE_sale");
- 4.测试:
返回顶部
6.2 @PreAuthorize
- 注解适合进入方法前的权限验证, @PreAuthorize 可以将登录用 户的 roles/permissions 参数传到方法中。
- 1.使用注解要首先开启注解功能!
@EnableGlobalMethodSecurity(prePostEnabled = true)
package com.zyx.securitydemo1;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
@SpringBootApplication()
@MapperScan("com.zyx.securitydemo1.mapper")
// 使用注解先要开启注解功能!
@EnableGlobalMethodSecurity(securedEnabled=true,prePostEnabled = true)
public class Securitydemo1Application {
public static void main(String[] args) {
SpringApplication.run(Securitydemo1Application.class, args);
}
}
@GetMapping("/testPreAuthorize")
@ResponseBody
@PreAuthorize("hasAnyAuthority('admin')")
public String testPreAuthorize(){
return "hello test_PreAuthorize";
}
// 权限集合
List<GrantedAuthority> authorities =
AuthorityUtils.commaSeparatedStringToAuthorityList("admin,ROLE_sale");
- 4.测试:
当我们注解需要的权限与授予的权限均为admin时,可以正常验证登陆;当修改注解里面,需要的权限为admins的时候,就会报403。
返回顶部
6.3 @PostAuthorize
- @PostAuthorize 注解使用并不多,在方法执行后再进行权限验证,适合验证带有返回值 的权限.
- **1.先开启注解功能: @EnableGlobalMethodSecurity(prePostEnabled = true) **
- 2.在控制器方法上添加注解:
@GetMapping("/testPostAuthorize")
@ResponseBody
@PostAuthorize("hasAnyAuthority('admins')")
public String testPostAuthorize(){
System.out.println("test_PreAuthorize。。。。。");
return "hello test_PreAuthorize";
}
// 权限集合
List<GrantedAuthority> authorities =
AuthorityUtils.commaSeparatedStringToAuthorityList("admin,ROLE_sale");
- 4.测试:
通过测试很明显看出,虽然页面显示403错误,但是后台输出了控制器中的内容,也就是说控制器的方法是先执行的,然后再进行的权限认证。
返回顶部
6.4 @PostFilter
- 权限验证之后对数据进行过滤 留下用户名是 admin1 的数据
- 在控制器方法上添加注解:
- 表达式中的 filterObject 引用的是方法返回值 List 中的某一个元素
@GetMapping("/getAll")
@PreAuthorize("hasRole('ROLE_sale')")
@PostFilter("filterObject.username == 'admin1'")
@ResponseBody
public List<Users> getAllUser(){
ArrayList<Users> list = new ArrayList<>();
list.add(new Users(11,"admin1","6666"));
list.add(new Users(22,"admin2","888"));
System.out.println(list);
return list;
}
- 测试:
返回顶部
6.5 @PreFilter
- 进入控制器之前对数据进行过滤
- 在控制器方法上添加注解:
@GetMapping("/getTestPreFilter")
@PreAuthorize("hasRole('ROLE_sale')")
@PreFilter(value = "filterObject.id%2==0")
@ResponseBody
public List<Users> getTestPreFilter(@RequestBody List<Users> list){
list.forEach(t-> {
System.out.println(t.getId()+"\t"+t.getUsername());
});
return list;
}
总结
返回顶部
七、用户注销
7.1 配置类中添加退出配置
// 退出
http.logout().logoutUrl("/logout").logoutSuccessUrl("/index").permitAll();
返回顶部
7.2 修改配置类,登陆后进入成功页面
@Override
protected void configure(HttpSecurity http) throws Exception {
// 退出
http.logout().logoutUrl("/logout").logoutSuccessUrl("/test/hello").permitAll();
// 403
http.exceptionHandling().accessDeniedPage("/403.html");
http.formLogin() // 自定义登陆表单
.loginPage("/login.html") // 登陆页面设置
.loginProcessingUrl("/user/login") // 登陆访问路径
.defaultSuccessUrl("/success.html").permitAll() // 登陆成功后,跳转的路径
.and().authorizeRequests()
// 指定哪些路径可以直接访问,不需认证
.antMatchers("/static/**", "/test/hello", "/user/login").permitAll(
.anyRequest().authenticated() // 映射任何请求,指定任何经过身份验证的用户都允许使用 URL
.and().csrf().disable(); // 关闭csrf防护
}
返回顶部
7.3 引入成功页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
登录成功
<a href="/logout"> >退出</a>
</body>
</html>
返回顶部
7.4 测试
- 登陆成功后进入success.html页面,点击退出后返回 hello index 信息页,此时已经退出,如果要访问 /test/index 路径则需要再次进行认证。
返回顶部
八、自动登陆
8.1 创建数据库表
CREATE TABLE `persistent_logins` (
`username` varchar(64) NOT NULL,
`series` varchar(64) NOT NULL,
`token` varchar(64) NOT NULL,
`last_used` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE
CURRENT_TIMESTAMP,
PRIMARY KEY (`series`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
返回顶部
8.2 修改配置类:注入数据源、配置操作数据库对象
@Configuration
public class SelfDFSecurityConfig extends WebSecurityConfigurerAdapter {
// 注入数据源
@Autowired
private DataSource dataSource;
// 配置对象
@Bean
public PersistentTokenRepository persistentTokenRepository(){
JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
jdbcTokenRepository.setDataSource(dataSource);
// 自动创建表
//jdbcTokenRepository.setCreateTableOnStartup(true);
return jdbcTokenRepository;
}
.....
}
返回顶部
8.3 修改配置类:实现自动登陆配置
.and().rememberMe().tokenRepository(persistentTokenRepository())
.tokenValiditySeconds(60) // 设置有效时长(S)
.userDetailsService(userDetailsService)
返回顶部
8.4 修改登陆界面
- 注意:复选框的
name
值必须为 remember-me
,底层封装好的!!!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/user/login" method="post">
用户名:<input type="text" name="username"/>
<br/>
密码:<input type="text" name="password"/>
<br/>
<input type="checkbox" name="remember-me" />自动登录
<br/>
<input type="submit" value="login"/>
</form>
</body>
</html>
返回顶部
8.5 测试
我们在登陆成功后,再次登陆发送请求,将不需要再次认证登陆,可以直接访问。
相应的数据库中会通过Security底层的封装,自动将信息存储到数据库中。
返回顶部