SpringSecurity
基于b站一个视频自己手打的SpringSecurity项目
pom.xml
<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.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</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>
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>login</title>
</head>
<body>
<form action="/login" method="post">
用户名:<input type="text" name="username" /></br>
密码: <input type="password" name="password" /></br>
<button type="submit" value="登录"/>
</form>
</body>
</html>
loginController.java
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class loginController {
// @RequestMapping("/login")
// public String login(){
// return "redirect:main.html";
// }
@RequestMapping("/toMain")
public String toMain(){
return "redirect:main.html";
}
@RequestMapping("/toError")
public String toError(){
return "redirect:error.html";
}
}
main.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>main</title>
</head>
<body>
<h3>登录成功</h3>
</body>
</html>
error.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>main</title>
</head>
<body>
登录失败,请重新登录<a href="login.html">跳转</a>
</body>
</html>
在测试类中测试Password(可跳过)
@Test
public void testPw(){
PasswordEncoder psw = new BCryptPasswordEncoder();
String encode = psw.encode("123456");//将明文密码“123456”进行加密
System.out.println(encode);//$2a$10$GVUOkD714k6DKhDfR7EIjOwxUQ0yuqfk8iygPx6i4ZCmFkq6YH0WO
boolean matches = psw.matches("123456", encode);//比较明文密码和加密后的密码
System.out.println(matches);//true
}
SecurityConfig.java
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.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
* security配置类
*/
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
MyAccessDeniedHandler handler;
@Override
protected void configure(HttpSecurity http) throws Exception {
//表单登录
http.formLogin()
.loginPage("/login.html")//自定义登录界面
.loginProcessingUrl("/login")//自定义登录逻辑
.successForwardUrl("/toMain")//登录成功后跳转界面,必须是POST方式
// .successHandler(new MyAuthenticationSuccessHandler("http://www.baidu.com"))
.failureForwardUrl("/toError");//登录失败后跳转界面,必须是POST方式
// .failureHandler(new MyAuthenticationFailureHandler("error.html"));
//异常处理
http.exceptionHandling()
.accessDeniedHandler(handler);
//授权
http.authorizeRequests()
//将login页面放行
.antMatchers("/login.html").permitAll()
//将error页面放行
.antMatchers("/error.html").permitAll()
.antMatchers("/image/**").permitAll()
// .antMatchers("/main1.html").hasAuthority("admin")
// .antMatchers("/main1.html").hasRole("abc")
//使所有界面都必须被认证,即需要先进行登录
.anyRequest().authenticated();
//自动判断登录的角色(authentication)是否有进入某地址(request)的权限,需要先创建下面的MyService类和MyServiceImpl类
//.anyRequest().access("@myServiceImpl.hasPermsion(request,authentication)");
//关闭csrf防护
http.csrf().disable();
}
@Bean
public PasswordEncoder psw(){
return new BCryptPasswordEncoder();
}
}
UserServiceImpl.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.*;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserDetailsService {
@Autowired
private PasswordEncoder psw;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//校验用户名,实际操作中需将用户名和数据库中的用户名进行比较
if(!"admin".equals(username)){
throw new UsernameNotFoundException("用户名错误");
}
//根据用户名校验密码
String password = psw.encode("123456");
//返回用户对象
return new User("admin",password, AuthorityUtils.createAuthorityList("admin,normal,/main.html"));//给用户创建两个权限:admin和normal
}
}
MyAuthenticationSuccessHandler.java
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@Component
public class MyAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
httpServletResponse.setStatus(HttpServletResponse.SC_FORBIDDEN);
httpServletResponse.setContentType("application/json;charset=utf-8");
PrintWriter writer = httpServletResponse.getWriter();
writer.write("{\"status\":\"403\",\"msg\":\"权限不足,请联系管理员\"}");
writer.flush();
writer.close();
}
}
MyAuthenticationSuccessHandler.java
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 自定义登录成功逻辑
*/
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
private final String Url;
public MyAuthenticationSuccessHandler(String url) {
this.Url = url;
}
@Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
Authentication authentication) throws IOException, ServletException {
httpServletResponse.sendRedirect(Url);
}
}
MyAuthenticationFailureHandler.java
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 自定义登录失败逻辑
*/
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {
private final String Url;
public MyAuthenticationFailureHandler(String url) {
this.Url = url;
}
@Override
public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
httpServletResponse.sendRedirect(Url);
}
}
MyService.java
import org.springframework.security.core.Authentication;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public interface MyService {
boolean hasPermsion(HttpServletRequest request, Authentication authentication);
}
MyServiceImpl.java
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import java.util.Collection;
@Service
public class MyServiceImpl implements MyService{
@Override
public boolean hasPermsion(HttpServletRequest request, Authentication authentication) {
String uri = request.getRequestURI();//当前登录的uri
Object principal = authentication.getPrincipal();//拿到当前的用户登录对象
if(principal instanceof UserDetails){//判断当前登录的用户是不是属于UserDetails对象
UserDetails userDetails = (UserDetails) principal;//强转
Collection<? extends GrantedAuthority> authorities = userDetails.getAuthorities();//拿到当前登录用户的权限集合
return authorities.contains(new SimpleGrantedAuthority(uri));
}
return false;
}
}