Spring Security中的用户注销
Posted 爱上口袋的天空
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Security中的用户注销相关的知识,希望对你有一定的参考价值。
实现过程:
登录成功后进入一个页面,点击退出后,无法访问需要权限的页面。
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>kgf-java-learning</artifactId>
<groupId>com.kgf.learning</groupId>
<version>1.0-SNAPSHOT</version>
<relativePath>../kgf-java-learning/pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.kgf.security</groupId>
<artifactId>spring-security-demo</artifactId>
<properties>
<lombok.version>1.18.16</lombok.version>
<fastjson.version>1.2.75</fastjson.version>
<druid.version>1.2.2</druid.version>
<mybatis-plus.version>3.4.1</mybatis-plus.version>
<mysql.version>5.1.49</mysql.version>
</properties>
<dependencies>
<!--引入mysql依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<!--引入mybatis-plus依赖-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<!-- 引入druid连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--lombok 用来简化实体类-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.2.11.RELEASE</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
application.yaml
server:
port: 8081
#spring:
# security:
# user:
# name: admin
# password: admin
spring:
datasource:
url: jdbc:mysql://192.168.1.13:3306/oss?userUnicode=true&characterEncoding=UTF-8&serverTimeZone=UTC
username: root
password: 897570
driver-class-name: com.mysql.jdbc.Driver
mybatis-plus: #注意:延迟加载不能在开启debug后,不能点开list信息,甚至不能把鼠标移到上面。否则在debug下会默认执行关联查询。
mapper-locations: classpath:/mappers/**/*.xml
type-aliases-package: com.kgf.security
login.html
<!DOCTYPE html>
<!-- 需要添加
<html xmlns:th="http://www.thymeleaf.org">
这样在后面的th标签就不会报错
-->
<html xmlns:th="http://www.thymeleaf.org">
<head lang="en">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>xx</title>
</head>
<body>
<h1>表单提交</h1>
<!-- 表单提交用户信息,注意字段的设置,直接是*{} -->
<form action="/user/login" method="post">
<input type="text" name="username" />
<input type="text" name="password" />
<input type="submit" />
</form>
</body>
</html>
success.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a href="/logout">退出</a>
</body>
</html>
unauth.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>没有访问权限</h1>
</body>
</html>
SecurityApplication.java
package com.kgf.security;
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;
@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)
@MapperScan(value = "com.kgf.security.mapper")
@SpringBootApplication
public class SecurityApplication {
public static void main(String[] args) {
SpringApplication.run(SecurityApplication.class,args);
}
}
Users.java
package com.kgf.security.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
@Data
public class Users {
private Integer id;
private String username;
private String password;
}
UsersMapper.java
package com.kgf.security.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.kgf.security.model.Users;
public interface UsersMapper extends BaseMapper<Users> {
}
MyUserDetailsService.java
package com.kgf.security.service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.kgf.security.mapper.UsersMapper;
import com.kgf.security.model.Users;
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 javax.annotation.Resource;
import java.util.List;
/***
* spring security查询用户的时候会自动到这个类中去查找
*/
@Service("userDetailsService")
public class MyUserDetailsService implements UserDetailsService {
@Resource
private UsersMapper usersMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
QueryWrapper<Users> usersQueryWrapper = new QueryWrapper<>();
usersQueryWrapper.eq("username",username);
Users users = usersMapper.selectOne(usersQueryWrapper);
if (users==null){
throw new UsernameNotFoundException("用户名不存在!");
}
//这里我们就不去查询数据库了,直接new一个对象
List<GrantedAuthority> authorityList = AuthorityUtils.commaSeparatedStringToAuthorityList("manager");
return new User(username,users.getPassword(),authorityList);
}
}
SecurityConfig.java
完整代码:
package com.kgf.security.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 SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsService userDetailsService; /*** * 设置登录的用户 * @param auth * @throws Exception */ @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { //这是使用内存的方式 // BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(); // String password = encoder.encode("123456"); // auth.inMemoryAuthentication().withUser("test").password(password).roles("admin"); //下面使用自定义接口实现类从数据库查询 auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); } @Override protected void configure(HttpSecurity http) throws Exception { http.formLogin() .loginPage("/login.html")//登录页面设置 .loginProcessingUrl("/user/login")//登录访问路径,这个不需要自己写controller,配置即可,这个是spring security自动完成 .defaultSuccessUrl("/success.html").permitAll()//登录成功之后跳转的路径 .and().authorizeRequests() .antMatchers("/","/test/hello","/user/login").permitAll()//设置这些路径可以直接访问,不需要认证 //1、hasAuthority方法 //.antMatchers("/test/index").hasAuthority("admin")//需要用户具有admin角色权限才行 //2、hasAnyAuthority方法 .antMatchers("/test/index").hasAnyAuthority("admin,manager")//需要用户具有admin角色权限才行 .anyRequest().authenticated() .and().exceptionHandling().accessDeniedPage("/unauth.html")//配置没有权限访问跳转自定义页面,必须配置在这里,配置在上面不起作用 .and().logout().logoutUrl("/logout").logoutSuccessUrl("/test/hello").permitAll()//退出 .and().csrf().disable();//关闭csrf防护 } /*** * 注入PasswordEncoder到spring中 * @return */ @Bean public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } }
TestController.java
package com.kgf.security.controller; import com.kgf.security.model.Users; import org.springframework.security.access.annotation.Secured; import org.springframework.security.access.prepost.PostFilter; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.ArrayList; import java.util.List; @RequestMapping("test") @RestController public class TestController { @RequestMapping("hello") public String test(){ return "hello security"; } @RequestMapping("index") public String index(){ return "hello index"; } @RequestMapping("unauth") public String unauth(){ return "unauth"; } @GetMapping("update") // @Secured({"ROLE_sale","ROLE_manager"}) @PreAuthorize("hasAnyAuthority('manager')") public String update() { return "hello update"; } @GetMapping("getAll") @PreAuthorize("hasAnyAuthority('manager')") @PostFilter("filterObject.username == '44'") public List<Users> getAllUser() { ArrayList<Users> list = new ArrayList<>(); list.add(new Users(1,"22","33")); list.add(new Users(2,"44","33")); return list; } }
测试:
退出:
点击退出之后访问/test/index,重新跳转到登录页面
以上是关于Spring Security中的用户注销的主要内容,如果未能解决你的问题,请参考以下文章
Spring Security OAuth2 AngularJS |注销流程
如何从 Spring Security 中的 java 代码登录用户?
java spring boot / spring security(HttpSecurity)中的会话到期时如何自动注销