Sprng boot + Spring security整合
程序员文章站
2022-04-19 22:31:53
...
Sprng boot + Spring security整合
本文主要介绍Sprng boot + Spring security实战整合,不涉及概念性内容,开发环境idea+jdk1.8+maven+Sprng boot 2.1.4
效果展示
输入任意路径被拦截并跳转至登录页面
输入错误用户名或密码
登录成功
访问home页面
导包
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.springsecurity</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.20</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-cas</artifactId>
<version>5.1.2.RELEASE</version>
</dependency>
<!-- security taglibs -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</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-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.24</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.1</version><!--$NO-MVN-MAN-VER$-->
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version><!--$NO-MVN-MAN-VER$-->
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
编写项目配置
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql:///test
spring.datasource.password=root
spring.datasource.username=root
#数据库连接池
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
#sql的xml文件配置
mybatis.mapper-locations=classpath:mapper/*.xml
实体类
User类
@AllArgsConstructor
@NoArgsConstructor
public class User implements UserDetails{
private Integer id;
private String username;
private String password;
private Boolean enabled;
private Boolean locked;
private List<Role> roles;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
for (Role role : roles) {
authorities.add(new SimpleGrantedAuthority(role.getName()));
}
return authorities;
}
public List<Role> getRoles() {
return roles;
}
public void setRoles(List<Role> roles) {
this.roles = roles;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
public void setEnabled(Boolean enabled) {
this.enabled = enabled;
}
public Boolean getLocked() {
return locked;
}
public void setLocked(Boolean locked) {
this.locked = locked;
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return username;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return !locked;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return enabled;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", enabled=" + enabled +
", locked=" + locked +
", roles=" + roles +
'}';
}
}
Role 类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Role {
private Integer id;
private String name;
private String nameZh;
}
dao层
mapper
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.springsecurity.demo.dao.MyUserDao">
<select id="loadUserByUsername" resultType="com.springsecurity.demo.pojo.User" parameterType="string">
select * from adminuser where username = #{username}
</select>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.springsecurity.demo.dao.MyUserDao">
<select id="loadUserByUsername" resultType="com.springsecurity.demo.pojo.User" parameterType="string">
select * from adminuser where username = #{username}
</select>
<select id="getUserRolesByUserId" resultType="com.springsecurity.demo.pojo.Role">
select * from role r left join user_role ur on r.id=ur.rid and ur.uid=#{userId}
</select>
</mapper>
MyUserDao
@Mapper
public interface MyUserDao {
/**
* 通过用户名获取用户信息
*
* @param username 用户名
* @return User 用户信息
*/
User loadUserByUsername(String username);
/**
* 通过用户id获取用户角色集合
*
* @param userId 用户id
* @return List<Role> 角色集合
*/
List<Role> getUserRolesByUserId(Integer userId);
}
下面进入最重要的一部分(划重点)
因为是spring boot环境所以我们首先要写好Spring security的Java配置
Spring security config配置
@SpringBootConfiguration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;
@Autowired
CustomAuthenticationFailureHandler customAuthenticationFailureHandler;
@Autowired
MyBCryptPasswordEncoder myBCryptPasswordEncoder;
@Autowired
UserService userService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().
//拦截除‘/’外的所有请求
antMatchers("/").
permitAll()
.anyRequest()
.authenticated()
.and()
//指定登录路径
.formLogin()
.loginPage("/login")
.permitAll()
//登录成功
.successHandler(customAuthenticationSuccessHandler)
//登录失败
.failureHandler(customAuthenticationFailureHandler)
.and();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//用户名密码验证
auth.userDetailsService(userService).passwordEncoder(myBCryptPasswordEncoder);
}
}
登录成功处理类
@Slf4j
@Component
public class CustomAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication auth) throws IOException, ServletException {
//得到登录的用户信息
User principal = (User) auth.getPrincipal();
response.setContentType("application/json;charset=utf-8");
PrintWriter out = response.getWriter();
response.setStatus(200);
Map<String, Object> map = new HashMap<>(16);
//密码置空
principal.setPassword("");
map.put("status",200);
map.put("msg",principal);
ObjectMapper om = new ObjectMapper();
out.write(om.writeValueAsString(map));
out.flush();
out.close();
}
}
登录失败处理类
@Slf4j
@Component
public class CustomAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
response.setContentType("application/json;charset=utf-8");
PrintWriter out = response.getWriter();
response.setStatus(401);
Map<String, Object> map = new HashMap<>(16);
map.put("status", 401);
if (e instanceof LockedException) {
map.put("msg", "账户被锁定,登录失败!");
} else if (e instanceof BadCredentialsException) {
map.put("msg", "账户名或密码输入错误,登录失败!");
} else if (e instanceof DisabledException) {
map.put("msg", "账户被禁用,登录失败!");
} else if (e instanceof CredentialsExpiredException) {
map.put("msg", "密码已过期,登录失败!");
} else {
map.put("msg", "登录失败!");
}
ObjectMapper om = new ObjectMapper();
out.write(om.writeValueAsString(map));
out.flush();
out.close();
}
}
用户名验证
@Service
public class UserService implements UserDetailsService {
@Resource
MyUserDao userDao;
@Override
public UserDetails loadUserByUsername(String s){
User user = userDao.loadUserByUsername(s);
if (user == null) {
throw new UsernameNotFoundException("该用户不存在!");
}
List<Role> roles = new ArrayList<>();
roles.add(new Role(1,"user","user"));
user.setRoles(roles);
return user;
}
}
密码验证
@Slf4j
@Component
public class MyBCryptPasswordEncoder extends BCryptPasswordEncoder {
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword){
//密码验证
//encodedPassword原始密码
//rawPassword输入的密码
if (encodedPassword.equals(rawPassword)){
return true;
}
return false;
}
}
最后加上一个controller和页面来感受一下我们的成果
controller
@Controller
public class TextController {
@RequestMapping("/")
public String toHome(){
return "/home";
}
@RequestMapping("/home")
public String toHomes(){
return "/home";
}
@RequestMapping("/login")
public String toLogin(){
return "/login";
}
}
登录页面
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org"
xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<title>Spring Security Example </title>
</head>
<body>
<div th:if="${param.error}">
Invalid username and password.
</div>
<div th:if="${param.logout}">
You have been logged out.
</div>
<form th:action="@{/login}" method="post">
<div><label> User Name : <input type="text" name="username"/> </label></div>
<div><label> Password: <input type="password" name="password"/> </label></div>
<div><input type="submit" value="Sign In"/></div>
</form>
</body>
</html>
home页面
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org" xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<meta charset="UTF-8">
<title>Spring Security Example</title>
</head>
<body>
<h1 th:inline="text">Hello [[${#httpServletRequest.remoteUser}]]!</h1>
<form th:action="@{/logout}" method="post">
<input type="submit" value="Sign Out"/>
</form>
</body>
</html>
上一篇: HTML中的一些常用标签
推荐阅读
-
详解Spring Boot Security
-
Spring Boot Security 结合 JWT 实现无状态的分布式API接口
-
Spring Boot整合elasticsearch的详细步骤
-
浅谈Spring Boot 整合ActiveMQ的过程
-
Spring Boot2.0整合ES5实现文章内容搜索实战
-
Spring Boot整合ElasticSearch实现多版本兼容的方法详解
-
Spring Boot整合mybatis并自动生成mapper和实体实例解析
-
spring boot整合CAS Client实现单点登陆验证的示例
-
spring boot整合quartz实现多个定时任务的方法
-
详解如何在spring boot中使用spring security防止CSRF攻击