在企业级项目中,认证与授权是安全模块的核心:
主流 Java 权限框架:Spring Security(Spring 生态原生,功能强大)、Apache Shiro(轻量易用),本文基于 Spring Security 实现权限控制。
权限控制依赖 7 张核心数据表,角色表为核心枢纽,用户、权限、菜单均与角色多对多关联:
|
1 2 3 4 5 6 7 8 9 10 |
<!-- Spring Security启动器 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <!-- Web依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> |
Spring Boot 启动时自动加载springSecurityFilterChain(FilterChainProxy),包含 15 个核心过滤器,关键过滤器作用:
继承WebSecurityConfigurerAdapter,实现匿名资源放行、自定义登录页、认证来源、权限规则配置:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
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.builders.WebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; /** * Spring Security核心配置类 */ @Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserService userService; /** * 配置静态资源匿名放行 */ @Override public void configure(WebSecurity web) throws Exception { // 放行登录页、静态资源、验证码接口 web.ignoring().antMatchers("/login.html", "/pages/**", "/validateCode/send4Login.do"); } /** * 配置认证来源(关联自定义UserService) */ @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userService).passwordEncoder(passwordEncoder()); } /** * 配置HTTP请求安全(登录、授权、退出) */ @Override protected void configure(HttpSecurity http) throws Exception { // 自定义表单登录 http.formLogin() .loginPage("/login.html") // 自定义登录页 .loginProcessingUrl("/login") // 登录请求接口 .usernameParameter("username") // 用户名参数 .passwordParameter("password") // 密码参数 .defaultSuccessUrl("/index.html"); // 登录成功跳转页 // 权限配置 http.authorizeRequests() .antMatchers("/pages/b.html").hasAuthority("add") // 需add权限 .antMatchers("/pages/c.html").hasRole("ADMIN") // 需ADMIN角色 .anyRequest().authenticated(); // 其余资源需登录 // 退出登录配置 http.logout() .logoutUrl("/logout") // 退出接口 .logoutSuccessUrl("/login.html"); // 退出成功跳转页 // 关闭CSRF防护(前后端分离可关闭) http.csrf().disable(); } /** * 密码加密器(BCrypt加密) */ @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } } |
实现UserDetailsService接口,重写loadUserByUsername方法,从数据库查询用户信息:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; 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.Component; import java.util.ArrayList; import java.util.HashMap; import java.util.Map;
@Component public class UserService implements UserDetailsService {
// 模拟数据库用户数据 private static Map<String, UserInfo> userMap = new HashMap<>();
@Autowired private BCryptPasswordEncoder passwordEncoder;
// 初始化加密用户数据 static { userMap.put("admin", new UserInfo("admin", new BCryptPasswordEncoder().encode("admin"))); userMap.put("user", new UserInfo("user", new BCryptPasswordEncoder().encode("123456"))); }
@Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { // 从数据库查询用户 UserInfo userInfo = userMap.get(username); if (userInfo == null) { throw new UsernameNotFoundException("用户名不存在"); }
// 封装权限/角色 ArrayList<GrantedAuthority> authorities = new ArrayList<>(); if ("admin".equals(username)) { authorities.add(new SimpleGrantedAuthority("add")); authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN")); }
// 返回Spring Security规范用户对象 return new User(userInfo.getUsername(), userInfo.getPassword(), authorities); } }
// 用户实体类 class UserInfo { private String username; private String password;
public UserInfo(String username, String password) { this.username = username; this.password = password; }
// getter/setter } |
在HttpSecurity中直接配置 URL 权限规则:
|
1 2 3 4 |
http.authorizeRequests() .antMatchers("/pages/b.html").hasAuthority("add") // 需add权限 .antMatchers("/pages/c.html").hasRole("ADMIN") // 需ADMIN角色 .anyRequest().authenticated(); |
|
1 2 3 4 |
@Configuration @EnableGlobalMethodSecurity(prePostEnabled = true) // 开启权限注解 public class WebSecurityConfig extends WebSecurityConfigurerAdapter { } |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;
@RestController @RequestMapping("/permission") public class PermissionController {
// 需add权限才可访问 @RequestMapping("/add") @PreAuthorize("hasAuthority('add')") public String add() { return "新增权限验证通过"; }
// 需ADMIN角色才可访问 @RequestMapping("/delete") @PreAuthorize("hasRole('ADMIN')") public String delete() { return "删除权限验证通过"; } } |
配置退出接口,请求/logout即可自动清除认证信息,跳转至登录页:
|
1 2 3 |
http.logout() .logoutUrl("/logout") // 退出请求路径 .logoutSuccessUrl("/login.html"); // 退出成功跳转页 |