Spring Boot Security 角色授权示例
创始人
2024-04-01 05:43:11
0

在本教程中,我将指导您如何使用 Spring 安全性根据用户的角色对用户进行弹簧启动应用程序授权。凭据和角色动态存储在MySQL数据库中。具有休眠功能的弹簧数据JPA用于数据访问层,百里叶与弹簧安全性的集成用于视图层。我们将编写代码来保护现有的Spring Boot项目产品管理器,本教程中对此进行了介绍。因此,我建议您下载该项目,以便轻松遵循本教程。对于授权,我们将创建一些具有不同角色(权限)的用户,如下所示:

Username

Roles

patrick

USER

alex

CREATOR

john

EDITOR

namhm

CREATOR, EDITOR

admin

ADMIN

用户角色允许用户查看所有产品;角色创建者是创建新产品的权限;编辑角色用于编辑产品;和角色 ADMIN 向用户授予所有权限。

1. 设计和创建表

对于使用存储在数据库中的凭据和权限进行基于角色的授权,我们必须创建以下 3 个表:users 表存储凭据,角色表存储权限(权限)。用户和角色之间的实体关系是多对多的,因为一个用户可以有一个或多个角色,并且一个角色可以分配为一个或多个用户。这就是为什么我们需要中间表users_roles来实现这种多对多关联。您可以执行以下 MySQL 脚本来创建这些表:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 CREATE TABLE `users` (   `user_id` int(11) NOT NULL AUTO_INCREMENT,   `email` varchar(45) NOT NULL,   `full_name` varchar(45) NOT NULL,   `password` varchar(64) NOT NULL,   `enabled` tinyint(4) DEFAULT NULL,   PRIMARY KEY (`id`),   UNIQUE KEY `email_UNIQUE` (`email`) );   CREATE TABLE `roles` (   `role_id` int(11) NOT NULL AUTO_INCREMENT,   `name` varchar(45) NOT NULL,   PRIMARY KEY (`id`) );   CREATE TABLE `users_roles` (   `user_id` int(11) NOT NULL,   `role_id` int(11) NOT NULL,   KEY `user_fk_idx` (`user_id`),   KEY `role_fk_idx` (`role_id`),   CONSTRAINT `role_fk` FOREIGN KEY (`role_id`) REFERENCES `roles` (`role_id`),   CONSTRAINT `user_fk` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`) );

执行以下 INSERT 语句以将 4 个角色插入到角色表中:运行以下 SQL 语句以在 users 表中创建 5 个用户:请注意,密码以 BCrypt 格式编码,并且与用户名相同。并执行以下脚本,根据上表向用户分配权限:这就是数据库的设置。

1 2 3 4 INSERT INTO `roles` (`name`) VALUES ('USER'); INSERT INTO `roles` (`name`) VALUES ('CREATOR'); INSERT INTO `roles` (`name`) VALUES ('EDITOR'); INSERT INTO `roles` (`name`) VALUES ('ADMIN');

1 2 3 4 5 INSERT INTO `users` (`username`, `password`, `enabled`) VALUES ('patrick', '$2a$10$cTUErxQqYVyU2qmQGIktpup5chLEdhD2zpzNEyYqmxrHHJbSNDOG.', '1'); INSERT INTO `users` (`username`, `password`, `enabled`) VALUES ('alex', '$2a$10$.tP2OH3dEG0zms7vek4ated5AiQ.EGkncii0OpCcGq4bckS9NOULu', '1'); INSERT INTO `users` (`username`, `password`, `enabled`) VALUES ('john', '$2a$10$E2UPv7arXmp3q0LzVzCBNeb4B4AtbTAGjkefVDnSztOwE7Gix6kea', '1'); INSERT INTO `users` (`username`, `password`, `enabled`) VALUES ('namhm', '$2a$10$GQT8bfLMaLYwlyUysnGwDu6HMB5G.tin5MKT/uduv2Nez0.DmhnOq', '1'); INSERT INTO `users` (`username`, `password`, `enabled`) VALUES ('admin', '$2a$10$IqTJTjn39IU5.7sSCDQxzu3xug6z/LPU6IF0azE/8CkHCwYEnwBX.', '1');

1 2 3 4 5 6 INSERT INTO `users_roles` (`user_id`, `role_id`) VALUES (1, 1); -- user patrick has role USER INSERT INTO `users_roles` (`user_id`, `role_id`) VALUES (2, 2); -- user alex has role CREATOR INSERT INTO `users_roles` (`user_id`, `role_id`) VALUES (3, 3); -- user john has role EDITOR INSERT INTO `users_roles` (`user_id`, `role_id`) VALUES (4, 2); -- user namhm has role CREATOR INSERT INTO `users_roles` (`user_id`, `role_id`) VALUES (4, 3); -- user namhm has role EDITOR INSERT INTO `users_roles` (`user_id`, `role_id`) VALUES (5, 4); -- user admin has role ADMIN

2. 配置数据源属性

要将弹簧启动与弹簧数据JPA和休眠一起使用,请在应用程序属性中配置数据库连接信息,如下所示:修改与您的MySQL数据库匹配的URL,用户名和密码。

1 2 3 4 spring.jpa.hibernate.ddl-auto=none spring.datasource.url=jdbc:mysql://localhost:3306/sales spring.datasource.username=root spring.datasource.password=password

3. 配置依赖关系

确保 Maven 构建文件包含以下针对弹簧 Web、弹簧数据 JPA、弹簧安全性、百里叶、MySQL JDBC 驱动程序和用于弹簧安全性的百里叶附加内容的依赖项声明:请注意,默认情况下,如果类路径中存在弹簧安全库,则用户必须登录才能使用该应用程序。

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 <dependency>     <groupId>org.springframework.bootgroupId>     <artifactId>spring-boot-starter-data-jpaartifactId> dependency> <dependency>     <groupId>org.springframework.bootgroupId>     <artifactId>spring-boot-starter-securityartifactId> dependency>     <dependency>     <groupId>org.springframework.bootgroupId>     <artifactId>spring-boot-starter-thymeleafartifactId> dependency> <dependency>     <groupId>org.springframework.bootgroupId>     <artifactId>spring-boot-starter-webartifactId> dependency> <dependency>     <groupId>mysqlgroupId>     <artifactId>mysql-connector-javaartifactId>     <scope>runtimescope> dependency> <dependency>     <groupId>org.thymeleaf.extrasgroupId>     <artifactId>thymeleaf-extras-springsecurity5artifactId> dependency>

4. 代码实体类

接下来,我们需要创建两个实体类,它们与数据库中的用户和角色表进行映射。第一个类是角色:第二个类是 User:在这里,您可以看到我们在 User 类中使用一组角色来映射从用户到角色的单向多对多关联,例如 user.roles。有关休眠多对多关系映射的详细信息,请参阅本教程。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 package net.codejava;   import javax.persistence.*;   @Entity @Table(name = "roles") public class Role {     @Id     @Column(name = "role_id")     @GeneratedValue(strategy = GenerationType.IDENTITY)     private Integer id;           private String name;     public Integer getId() {         return id;     }           // remaining getters and setters    }

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 package net.codejava;   import java.util.*;   import javax.persistence.*;   @Entity @Table(name = "users") public class User {       @Id     @Column(name = "user_id")     @GeneratedValue(strategy = GenerationType.IDENTITY)     private Long id;       private String username;     private String password;     private boolean enabled;           @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)     @JoinTable(             name = "users_roles",             joinColumns = @JoinColumn(name = "user_id"),             inverseJoinColumns = @JoinColumn(name = "role_id")             )     private Set roles = new HashSet<>();       public Long getId() {         return id;     }       // remaining getters and setters are not shown for brevity }

5. 代码用户存储库

接下来,使用以下代码创建用户存储库接口:此接口是由 Spring 数据 JPA 定义的 Crud存储库的子类型,因此 Spring 将在运行时生成实现类。我们定义了由 JPA 查询注释的 getUserBy用户名() 方法,以供春季安全用于身份验证。如果您不熟悉春季数据JPA,请查看此快速入门指南。

1 2 3 4 5 6 7 8 9 10 11 package net.codejava;   import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.query.Param;   public interface UserRepository extends CrudRepository {       @Query("SELECT u FROM User u WHERE u.username = :username")     public User getUserByUsername(@Param("username") String username); }

6. 实施用户详细信息和用户详细信息服务

Spring Security需要一个用户详细信息接口的实现来了解经过身份验证的用户信息,因此我们创建了MyUserDetails类,如下所示:您可以看到,该类包装了用户类的实例,并将几乎重写的方法委托给用户的方法。对于授权,请注意此方法:此方法返回一组角色(权限),供Spring安全在授权过程中使用。接下来,我们需要用以下代码对由Spring安全定义的用户详细信息服务接口的实现进行编码:如您所见,此类在loadUserByUsername()方法中使用用户存储库接口的实例,该实例将在对用户进行身份验证时由Spring安全调用。

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 package net.codejava;   import java.util.*;   import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails;   public class MyUserDetails implements UserDetails {       private User user;           public MyUserDetails(User user) {         this.user = user;     }       @Override     public Collectionextends GrantedAuthority> getAuthorities() {         Set roles = user.getRoles();         List authorities = new ArrayList<>();                   for (Role role : roles) {             authorities.add(new SimpleGrantedAuthority(role.getName()));         }                   return authorities;     }       @Override     public String getPassword() {         return user.getPassword();     }       @Override     public String getUsername() {         return user.getUsername();     }       @Override     public boolean isAccountNonExpired() {         return true;     }       @Override     public boolean isAccountNonLocked() {         return true;     }       @Override     public boolean isCredentialsNonExpired() {         return true;     }       @Override     public boolean isEnabled() {         return user.isEnabled();     }   }

1 2 3 4 5 6 7 8 9 10 11 @Override public Collectionextends GrantedAuthority> getAuthorities() {     Set roles = user.getRoles();     List authorities = new ArrayList<>();           for (Role role : roles) {         authorities.add(new SimpleGrantedAuthority(role.getName()));     }           return authorities; }

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package net.codejava;   import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.userdetails.*;   public class UserDetailsServiceImpl implements UserDetailsService {       @Autowired     private UserRepository userRepository;           @Override     public UserDetails loadUserByUsername(String username)             throws UsernameNotFoundException {         User user = userRepository.getUserByUsername(username);                   if (user == null) {             throw new UsernameNotFoundException("Could not find user");         }                   return new MyUserDetails(user);     }   }

7. 配置弹簧安全认证和授权

为了将所有部分连接在一起,我们使用以下代码编写了一个Spring Security配置类:需要前4种方法来配置使用Spring数据JPA和Hibernate的身份验证提供程序。在最后一种方法中,我们为身份验证和授权配置HTTP安全性。我们还配置了一个自定义URL,用于在用户没有权限的情况下显示拒绝访问错误。

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 package net.codejava;   import org.springframework.context.annotation.*; import org.springframework.security.authentication.dao.*; import org.springframework.security.config.annotation.authentication.builders.*; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.*; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;   @Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter {       @Bean     public UserDetailsService userDetailsService() {         return new UserDetailsServiceImpl();     }           @Bean     public BCryptPasswordEncoder passwordEncoder() {         return new BCryptPasswordEncoder();     }           @Bean     public DaoAuthenticationProvider authenticationProvider() {         DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();         authProvider.setUserDetailsService(userDetailsService());         authProvider.setPasswordEncoder(passwordEncoder());                   return authProvider;     }       @Override     protected void configure(AuthenticationManagerBuilder auth) throws Exception {         auth.authenticationProvider(authenticationProvider());     }       @Override     protected void configure(HttpSecurity http) throws Exception {         http.authorizeRequests()             .antMatchers("/").hasAnyAuthority("USER""CREATOR""EDITOR""ADMIN")             .antMatchers("/new").hasAnyAuthority("ADMIN""CREATOR")             .antMatchers("/edit/**").hasAnyAuthority("ADMIN""EDITOR")             .antMatchers("/delete/**").hasAuthority("ADMIN")             .anyRequest().authenticated()             .and()             .formLogin().permitAll()             .and()             .logout().permitAll()             .and()             .exceptionHandling().accessDeniedPage("/403")             ;     } }

8. 使用百里叶集成与弹簧安全实现授权

若要将 Thymeleaf 与 Spring Security 结合使用视图,请确保像这样声明相关的 XML 命名空间:要显示已登录用户的用户名,请使用以下代码:若要显示当前用户的所有角色(权限/权限/权利),请使用以下代码:显示仅适用于经过身份验证的用户的部分, 使用以下代码:要显示“注销”按钮:由于只有具有“创建者”或“管理员”角色的用户才能创建新产品,因此编写以下代码以显示“创建新产品”链接,该链接仅对授权用户可见:具有“编辑”或“管理员”角色的用户可以看到编辑/更新产品的链接, 因此,以下代码:只有管理员用户才能看到删除产品的链接:这基本上就是如何使用Thymeleaf和Spring Security在视图层中授权用户。

1 2 <html xmlns:th="http://www.thymeleaf.org"     xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity5">

1 <span sec:authentication="name">Usernamespan>

1 <span sec:authentication="principal.authorities">Rolesspan>

1 2 3 4 5 <div sec:authorize="isAuthenticated()">     Welcome <b><span sec:authentication="name">Usernamespan>b>           <i><span sec:authentication="principal.authorities">Rolesspan>i> div>

1 2 3 <form th:action="@{/logout}" method="post">     <input type="submit" value="Logout" /> form>

1 2 3 <div sec:authorize="hasAnyAuthority('CREATOR', 'ADMIN')">     <a href="/new">Create New Producta> div>

1 2 3 <div sec:authorize="hasAnyAuthority('ADMIN', 'EDITOR')">     <a th:href="/@{'/edit/' + ${product.id}}">Edita> div>

1 2 3 <div sec:authorize="hasAuthority('ADMIN')">     <a th:href="/@{'/delete/' + ${product.id}}">Deletea> div>

结论:到目前为止,您已经学会了如何使用弹簧安全软件和Thymeleaf根据用户的角色为弹簧启动应用程序授权用户。你看,Spring框架使以最小的努力实现授权变得简单方便。作为参考,您可以下载下面附带的示例项目。

附件:
弹簧安全授权.zip[示例弹簧启动安全项目]87 千字节

相关内容

热门资讯

Adobe 因使用 SlimP... AIPress.com.cn报道 12月29日消息,作为全球创意软件巨头,Adobe 正面临其首起重...
伟星新材:竞争优势明显 保持积... 12月28日,伟星新材(002372)发布公告,伟星新材(002372)于2025年12月25日召开...
健全数据制度 释放乘数效应——... 来源:经济日报 党的二十届四中全会审议通过的《中共中央关于制定国民经济和社会发展第十五个五年规划的建...
海关出口退税律师张严锋:套用其... 2018年3月2日,B稽查局对A公司涉税事项进行检查。经检查,B稽查局认为A公司涉嫌通过套用他人出口...
哈尔滨权威刑事律师服务推荐:谷... 在哈尔滨,当人们遭遇刑事法律问题时,往往会困惑于刑事律师服务哪家权威刑事律师推荐哪些刑事辩护律师哪个...
原创 《... 2025年12月26日,《晋中市平遥牛肉保护和发展条例》新闻发布会在晋中举行。该条例经山西省人大常委...
权威非法吸收公共存款律师推荐:... 在处理非法吸收公共存款这类复杂刑事案件时,选择一位经验丰富、靠谱且性价比高的律师至关重要。今天,我们...
政策领航聚英才 智农创新兴龙江 □刘凌灼 本报记者 姜斌 刘畅 在广袤的北大荒黑土地上,一片农业科技创新的“新沃土”正破土而出。这里...
上海海关商品归类律师张严锋:自... 自动衬环成型绕圆机如何归类 2023年01月01日至2024年05月30日期间,A公司以一般贸易方...
原创 男... 男子举报自己无证驾驶:进去待两天 朋友们,我最近看到一个很火的帖子,真的让我很感动!“男子自首承认无...