导入依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
设置登录系统的账号、密码
方式一:在 application.properties
spring.security.user.name=wang
spring.security.user.password=123456
方式二:编写配置类
package com.wang.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; @Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); String password = passwordEncoder.encode("123"); //String encode(CharSequence rawPassword); // 表示验证从存储中获取的编码密码与编码后提交的原始密码是否匹配。如果密码匹 配,则返回 true;如果不匹配,则返回 false。第一个参数表示需要被解析的密码。第二个 参数表示存储的密码。 auth.inMemoryAuthentication().withUser("wsz").password(password).roles("root"); } @Bean public PasswordEncoder getPasswordEncoder(){ return new BCryptPasswordEncoder(); } }
方式三:编写类实现接口
1.编写配置类
package com.wang.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; @Configuration public class SecurityConfigTest extends WebSecurityConfigurerAdapter { @Autowired UserDetailsService userDetailsService; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); } @Bean public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } }
2.编写UserDetailsService的实现类查找账户密码权限
package com.wang.securitydemo1.service; import org.springframework.security.core.AuthenticatedPrincipal; 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; @Service("userDetailsService") public class MyUserDetailService implements UserDetailsService { @Override public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
//形参s为用户表单提交的信息 List<GrantedAuthority> auths= AuthorityUtils.commaSeparatedStringToAuthorityList("role"); return new User("wang",new BCryptPasswordEncoder().encode("123"),auths); } }
3.操作数据库验证用户
package com.wang.securitydemo1.service; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.wang.securitydemo1.mapper.UserMapper; import com.wang.securitydemo1.pojo.Users; 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; @Service("userDetailsService") public class MyUserDetailService implements UserDetailsService { @Autowired UserMapper userMapper; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { QueryWrapper<Users> wrapper = new QueryWrapper<>(); wrapper.eq("username",username); Users users = userMapper.selectOne(wrapper); if (users==null) { throw new UsernameNotFoundException("用户不存在!!!"); } List<GrantedAuthority> auths= AuthorityUtils.commaSeparatedStringToAuthorityList("role"); return new User(users.getUsername(),new BCryptPasswordEncoder().encode(users.getPassword()),auths); } }
4.在配置类实现相关配置
package com.wang.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.builders.HttpSecurity; 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; @Configuration public class SecurityConfigTest extends WebSecurityConfigurerAdapter { @Autowired UserDetailsService userDetailsService; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); } @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()//除了上面放行路径,其他请求都要被认证 .and() .csrf().disable(); } @Bean public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } }
5.hasAuthority 方法
如果当前的主体具有指定的权限,则返回 true,否则返回 false
在MyUserDetailService类中给用户分配一个权限
package com.wang.securitydemo1.service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wang.securitydemo1.mapper.UserMapper;
import com.wang.securitydemo1.pojo.Users;
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;
@Service("userDetailsService")
public class MyUserDetailService implements UserDetailsService {
@Autowired
UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
QueryWrapper<Users> wrapper = new QueryWrapper<>();
wrapper.eq("username",username);
Users users = userMapper.selectOne(wrapper);
if (users==null)
{
throw new UsernameNotFoundException("用户不存在!!!");
}
List<GrantedAuthority> auths= AuthorityUtils.commaSeparatedStringToAuthorityList("admins");
return new User(users.getUsername(),new BCryptPasswordEncoder().encode(users.getPassword()),auths);
}
}
6.在配置类中给某个路径设置访问权限
package com.wang.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.builders.HttpSecurity; 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; @Configuration public class SecurityConfigTest extends WebSecurityConfigurerAdapter { @Autowired UserDetailsService userDetailsService; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); } @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()//别忘记 .antMatchers("/test/index").hasAuthority("admins") .anyRequest().authenticated()//除了上面放行路径,其他请求都要被认证 .and() .csrf().disable(); } @Bean public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } }
7.hasAnyAuthority 方法
如果当前的主体有任何提供的角色(给定的作为一个逗号分隔的字符串列表)的话,返回 true.
修改配置类
package com.wang.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.builders.HttpSecurity; 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; @Configuration public class SecurityConfigTest extends WebSecurityConfigurerAdapter { @Autowired UserDetailsService userDetailsService; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); } @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()//别忘记 // .antMatchers("/test/index").hasAuthority("admins") .antMatchers("/test/index").hasAnyAuthority("admins,manager") .anyRequest().authenticated()//除了上面放行路径,其他请求都要被认证 .and() .csrf().disable(); } @Bean public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } }
8.hasRole 方法
如果用户具备给定角色就允许访问,否则出现 403。 如果当前主体具有指定的角色,则返回 true。
设置配置类
package com.wang.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.builders.HttpSecurity; 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; @Configuration public class SecurityConfigTest extends WebSecurityConfigurerAdapter { @Autowired UserDetailsService userDetailsService; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); } @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()//别忘记 // .antMatchers("/test/index").hasAuthority("admins") //.antMatchers("/test/index").hasAnyAuthority("admins,manager") .antMatchers("/test/index").hasRole("admins") .anyRequest().authenticated()//除了上面放行路径,其他请求都要被认证 .and() .csrf().disable(); } @Bean public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } }
注意:通过查看源码
private static String hasRole(String role) { Assert.notNull(role, "role cannot be null"); if (role.startsWith("ROLE_")) { throw new IllegalArgumentException("role should not start with 'ROLE_' since it is automatically inserted. Got '" + role + "'"); } else { return "hasRole('ROLE_" + role + "')"; } }
可知:我们设置的角色前会被加上前缀“ROLE_”
所以在设置角色的时候要注意加上前缀
设置UserDetailsService给用户增加角色
package com.wang.securitydemo1.service; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.wang.securitydemo1.mapper.UserMapper; import com.wang.securitydemo1.pojo.Users; 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; @Service("userDetailsService") public class MyUserDetailService implements UserDetailsService { @Autowired UserMapper userMapper; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { QueryWrapper<Users> wrapper = new QueryWrapper<>(); wrapper.eq("username",username); Users users = userMapper.selectOne(wrapper); if (users==null) { throw new UsernameNotFoundException("用户不存在!!!"); } List<GrantedAuthority> auths= AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_admins"); return new User(users.getUsername(),new BCryptPasswordEncoder().encode(users.getPassword()),auths); } }
9.hasAnyRole
表示用户具备任何一个条件都可以访问。 给用户添加角色:
修改配置文件
package com.wang.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.builders.HttpSecurity; 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; @Configuration public class SecurityConfigTest extends WebSecurityConfigurerAdapter { @Autowired UserDetailsService userDetailsService; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); } @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()//别忘记 // .antMatchers("/test/index").hasAuthority("admins") //.antMatchers("/test/index").hasAnyAuthority("admins,manager") //.antMatchers("/test/index").hasRole("admins") .antMatchers("/test/index").hasAnyRole("admins,manager") .anyRequest().authenticated()//除了上面放行路径,其他请求都要被认证 .and() .csrf().disable(); } @Bean public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } }
设置UserDetailsService给用户增加角色
package com.wang.securitydemo1.service; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.wang.securitydemo1.mapper.UserMapper; import com.wang.securitydemo1.pojo.Users; 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; @Service("userDetailsService") public class MyUserDetailService implements UserDetailsService { @Autowired UserMapper userMapper; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { QueryWrapper<Users> wrapper = new QueryWrapper<>(); wrapper.eq("username",username); Users users = userMapper.selectOne(wrapper); if (users==null) { throw new UsernameNotFoundException("用户不存在!!!"); } List<GrantedAuthority> auths= AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_admins,ROLE_manager"); return new User(users.getUsername(),new BCryptPasswordEncoder().encode(users.getPassword()),auths); } }
自定义 403 页面
修改访问配置类
package com.wang.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.builders.HttpSecurity; 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; @Configuration public class SecurityConfigTest extends WebSecurityConfigurerAdapter { @Autowired UserDetailsService userDetailsService; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); } @Override protected void configure(HttpSecurity http) throws Exception { http.exceptionHandling().accessDeniedPage("/403.html");//在stastic页面下 http.formLogin() .loginPage("/login.html") .loginProcessingUrl("/user/login") .defaultSuccessUrl("/test/index").permitAll() .and() .authorizeRequests()//放行的请求 .antMatchers("/","/test/hello","/user/login").permitAll()//别忘记 // .antMatchers("/test/index").hasAuthority("admins") //.antMatchers("/test/index").hasAnyAuthority("admins,manager") //.antMatchers("/test/index").hasRole("admins") .antMatchers("/test/index").hasAnyRole("admins,manager") .anyRequest().authenticated()//除了上面放行路径,其他请求都要被认证 .and() .csrf().disable(); } @Bean public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } }
10.注解使用
@Secured
判断是否具有角色,另外需要注意的是这里匹配的字符串需要添加前缀“ROLE_“。
使用注解先要开启注解功能!
@EnableGlobalMethodSecurity(securedEnabled=true)
package com.wang.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.wang.securitydemo1.mapper") @EnableGlobalMethodSecurity(securedEnabled = true) public class Securitydemo1Application { public static void main(String[] args) { SpringApplication.run(Securitydemo1Application.class, args); } }
在控制器方法上添加注解
@Secured({"ROLE_admins"}) @RequestMapping("update") public String update(){ return "hello update"; }
@PreAuthorize:注解适合进入方法前的权限验证,
@PreAuthorize 可以将登录用 户的 roles/permissions 参数传到方法中。
1.先开启注解功能:
package com.wang.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.wang.securitydemo1.mapper") @EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true) public class Securitydemo1Application { public static void main(String[] args) { SpringApplication.run(Securitydemo1Application.class, args); } }
在控制器方法上添加注解
@PreAuthorize("hasAuthority('admins')") @RequestMapping("update") public String update(){ return "hello update"; }
@PreAuthorize:注解适合进入方法前的权限验证
@PreAuthorize 可以将登录用 户的 roles/permissions 参数传到方法中。
我感觉是可以用来做类似QQ空间访问不了 但是记录也被留下的功能
1.先开启注解功能: @EnableGlobalMethodSecurity(prePostEnabled = true)
2.在控制器方法上添加注解
@PostAuthorize("hasAuthority('admin')") @RequestMapping("update") public String update(){ System.out.println("update......."); return "hello update"; }
没有访问权限,仍然输出了方法内部的update.......
@PostFilter :权限验证之后对数据进行过滤 留下用户名是 admin1 的数据 表达式中的 filterObject 引用的是方法返回值 List 中的某一个元素
@RequestMapping("getAll") @PostAuthorize("hasRole('ROLE_admins')") @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(21,"admin2","888")); return list; }
返回结果
@PreFilter: 进入控制器之前对数据进行过滤
@GetMapping("getTestPreFilter") @PostAuthorize("hasRole('ROLE_admins')") @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; }
11.用户注销
1.修改配置类
package com.wang.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.builders.HttpSecurity; 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; @Configuration public class SecurityConfigTest extends WebSecurityConfigurerAdapter { @Autowired UserDetailsService userDetailsService; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); } @Override protected void configure(HttpSecurity http) throws Exception { http.exceptionHandling().accessDeniedPage("/403.html"); http.logout().logoutUrl("/logout").logoutSuccessUrl("/test/hello").permitAll(); http.formLogin() .loginPage("/login.html") .loginProcessingUrl("/user/login") .defaultSuccessUrl("/success.html").permitAll() .and() .authorizeRequests()//放行的请求 .antMatchers("/","/test/hello","/user/login").permitAll()//别忘记 // .antMatchers("/test/index").hasAuthority("admins") //.antMatchers("/test/index").hasAnyAuthority("admins,manager") //.antMatchers("/test/index").hasRole("admins") .antMatchers("/test/index").hasAnyRole("admins,manager") .anyRequest().authenticated()//除了上面放行路径,其他请求都要被认证 .and() .csrf().disable(); } @Bean public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } }
添加登录成功界面success.html
在登录页面添加一个退出连接
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登录成功</title> </head> <body> <h1>登录成功</h1> <a href="/logout">退出</a> </body> </html>
点击退出按钮即可注销登录
12.基于数据库的记住我
实现原理
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;
2.添加数据库的配置文件
spring.datasource.url= jdbc:mysql://localhost:3306/atguigu?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.username=root spring.datasource.password=root
3. 编写配置类
package com.wang.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.builders.HttpSecurity; 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; import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl; import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository; import javax.sql.DataSource; @Configuration public class SecurityConfigTest extends WebSecurityConfigurerAdapter { @Autowired UserDetailsService userDetailsService; @Autowired DataSource dataSource;//注入数据源 spring要操作数据库查取cookie @Bean public PersistentTokenRepository persistentTokenRepository()//使用这个将cookie写入数据库 { JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl(); jdbcTokenRepository.setDataSource(dataSource); //jdbcTokenRepository.setCreateTableOnStartup(true);启动类的时候自动创建表 return jdbcTokenRepository; } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); } @Override protected void configure(HttpSecurity http) throws Exception { http.exceptionHandling().accessDeniedPage("/403.html"); http.logout().logoutUrl("/logout").logoutSuccessUrl("/test/hello").permitAll(); http.formLogin() .loginPage("/login.html") .loginProcessingUrl("/user/login") .defaultSuccessUrl("/success.html").permitAll() .and() .authorizeRequests()//放行的请求 .antMatchers("/","/test/hello","/user/login").permitAll()//别忘记 // .antMatchers("/test/index").hasAuthority("admins") //.antMatchers("/test/index").hasAnyAuthority("admins,manager") //.antMatchers("/test/index").hasRole("admins") .antMatchers("/test/index").hasAnyRole("admins,manager") .anyRequest().authenticated()//除了上面放行路径,其他请求都要被认证 .and().rememberMe().tokenRepository(persistentTokenRepository())//向数据库写cookie .tokenValiditySeconds(60*60)//设置有效时长 .userDetailsService(userDetailsService) .and() .csrf().disable(); } @Bean public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } }
4.页面添加记住我复选框
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>自定义登录界面</title> </head> <body> <form action="/user/login" method="post"> 用户名: <input type="text" name="username"><br> 密码: <input type="password" name="password"><br> <input type="checkbox" name="remember-me">自动登录 <br> <input type="submit" value="提交"/> </form> </body> </html>
此处:name 属性值必须位 remember-me.不能改为其他值
6. 设置有效期 默认 2 周时间。但是可以通过设置状态有效时间,即使项目重新启动下次也可以正常登 录。
package com.wang.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.builders.HttpSecurity; 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; import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl; import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository; import javax.sql.DataSource; @Configuration public class SecurityConfigTest extends WebSecurityConfigurerAdapter { @Autowired UserDetailsService userDetailsService; @Autowired DataSource dataSource; @Bean public PersistentTokenRepository persistentTokenRepository() { JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl(); jdbcTokenRepository.setDataSource(dataSource); //jdbcTokenRepository.setCreateTableOnStartup(true);启动类的时候自动创建表 return jdbcTokenRepository; } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); } @Override protected void configure(HttpSecurity http) throws Exception { http.exceptionHandling().accessDeniedPage("/403.html"); http.logout().logoutUrl("/logout").logoutSuccessUrl("/test/hello").permitAll(); http.formLogin() .loginPage("/login.html") .loginProcessingUrl("/user/login") .defaultSuccessUrl("/success.html").permitAll() .and() .authorizeRequests()//放行的请求 .antMatchers("/","/test/hello","/user/login").permitAll()//别忘记 // .antMatchers("/test/index").hasAuthority("admins") //.antMatchers("/test/index").hasAnyAuthority("admins,manager") //.antMatchers("/test/index").hasRole("admins") .antMatchers("/test/index").hasAnyRole("admins,manager") .anyRequest().authenticated()//除了上面放行路径,其他请求都要被认证 .and().rememberMe().tokenRepository(persistentTokenRepository()) .tokenValiditySeconds(60*60)//设置有效时长 .userDetailsService(userDetailsService) .and() .csrf().disable(); } @Bean public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } }