1、实现UserDetails接口
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User implements UserDetails {
private String username;
private String password;
private Collection<GrantedAuthority> authorities;
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
2、实现UserDetailsService接口
import org.example.entity.User;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = null;
if (username.equals("admin")) {
//创建用户admin,并设置密码123456
user = new User(username, "123456", new ArrayList<>());
//手动为用户admin添加角色:role(角色标识,必须在前面加上ROLE_才可以)
user.getAuthorities().add((GrantedAuthority) () -> "ROLE_admin");
}
if (username.equals("zhangsan")) {
//创建用户zhangsan,并设置密码123456
user = new User(username, "123456", new ArrayList<>());
//手动为用户zhangsan添加权限:sys:test:userTest
user.getAuthorities().add((GrantedAuthority) () -> "sys:test:userTest");
}
if (user == null) {
throw new UsernameNotFoundException("用户不存在");
}
return user;
}
}
3、实现AuthenticationProvider接口
UserAuthenticationProvider
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
/**
* 自定义认证处理
*/
@Component("authenticationProvider")
public class UserAuthenticationProvider implements AuthenticationProvider {
@Autowired
private UserDetailsServiceImpl userDetailsService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = authentication.getName();
String password = (String) authentication.getCredentials();
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
if (!password.equals(userDetails.getPassword())) {
throw new BadCredentialsException("密码不正确,请重新登录!");
}
return new UsernamePasswordAuthenticationToken(username, password, userDetails.getAuthorities());
}
@Override
public boolean supports(Class<?> aClass) {
return true;
}
}
4、重写UserWebSecurityConfigurerAdapter方法
提供自定义验证
import org.springframework.beans.factory.annotation.Autowired;
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;
@Configuration
public class UserWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
//自定义认证逻辑处理
@Autowired
private UserAuthenticationProvider authenticationProvider;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
//禁用csrf
.csrf()
.disable()
//用户登录
.formLogin()
.loginPage("/login.html")
.loginProcessingUrl("/login")//自定义登录请求路径
//请求过滤
.and()
.authorizeRequests()
.antMatchers("/login.html", "/login").anonymous()//登录页与登录请求,只允许匿名访问
.anyRequest().authenticated();//除此之外,其他请求均需要登录后才可以访问
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider);
}
}
5、重写测试接口类
import org.example.common.AjaxResult;
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;
@RestController
@RequestMapping
public class TestController {
@GetMapping("test")
public AjaxResult test() {
return AjaxResult.success("test success");
}
@PreAuthorize("hasAuthority('sys:test:userTest')")
@GetMapping("userTest")
public AjaxResult userTest() {
return AjaxResult.success("userTest success:hasAuthority('sys:test:userTest')");
}
@PreAuthorize("hasRole('admin')")
@GetMapping("adminTest")
public AjaxResult adminTest() {
return AjaxResult.success("adminTest success:hasRole('admin')");
}
}
6、启动项目
这时发现,控制台中没有再提供默认密码了。标识我们自定义认证配置成功了。
7、测试
【测试1】访问测试接口:http://localhost:8080/test
【结论1】未登录时访问系统,默认重定向到登录页
【测试2】访问登录页:http://localhost:8080/login.html(输入错误账号:test/123456)
【结论2】账号错误时,默认重定向到登录页
【测试3】访问登录页:http://localhost:8080/login.html(输入错误密码:admin/12345678)
【结论3】密码错误时,默认重定向到登录页
【测试4】访问登录页:http://localhost:8080/login.html(输入正确密码:admin/123456)
【结论4】登录成功时,默认重定向到首页
【测试5】再次访问测试接口:http://localhost:8080/test
【结论5】访问成功,返回正确的json数据
【测试6】访问测试接口:http://localhost:8080/adminTest
【结论6】访问成功,返回正确的json数据
【测试7】访问测试接口:http://localhost:8080/userTest
【结论7】访问失败,返回错误状态码403(无授权)
【测试8】访问登出接口:http://localhost:8080/logout
【结论8】访问成功,默认重定向到登录页