Bạn có chắc chắn muốn xóa bài viết này không ?
Bạn có chắc chắn muốn xóa bình luận này không ?
[Spring Security + JWT] Phần 1 - Chuẩn bị đồ nghề và tạo thử một api
Xin chào các bạn đọc, trong seri này mình dự định sẽ chia sẻ cách dùng spring security để phân quyền trong web service, cách đọc ghi một JWT, rồi tạo thử một vài api để test Đây là lần đầu tiên mình viết một bài trên kipalog, nên có thể có nhiều thiếu sót, trong bài viết có chỗ nào chưa đúng các anh chị em góp ý cho mình với ạ, mình xin cảm ơn!
Công nghệ sử dụng
- Spring boot: để tạo và phát triển ứng dụng nhanh
- Spring Web: cái này để mình tạo web app, ở đây gọi là web service và mình dùng tiêu chuẩn restful api.
- Spring Security: còn cái spring security là để xác thực, phân quyền, mã hóa mật khẩu,...
- Spring Jpa: để mình tương tác với data.
- JWT (JSON Web Token): ở đây sẽ là một cái chuỗi loằng ngoằng mà server tạo ra cho client, để client ném lên server, server sẽ đọc thông tin trong đó để xử lý.
-
MySQL: là một hệ quản trị cơ sở dữ liệu mà nguồn mở. tóm lại dữ liệu sẽ được mình lưu vào đây
- Có thể còn thêm
Môi trường:
-
Java 15: cái này mình tiện tay nên cứ phang bản mới nhất thôi
các bạn dùng JAVA 8 trở lên là được rồi
- MySQL 8
Công cụ:
- IntelliJ IDEA
- HeidiSQL
- Postman
Bắt đầu chiến thôi
Thư viện sử dụng
Ở đây mình dùng maven nhé
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
<dependency>
<groupId>com.nimbusds</groupId>
<artifactId>nimbus-jose-jwt</artifactId>
<version>8.8</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.19</version>
</dependency>
Tạo database + config application.properties base
- Mình tạo database với tên demo_springjwt
- Rồi trong application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/demo_springjwt
spring.datasource.username=demo_springjwt
spring.datasource.password=
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
spring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate5.SpringSessionContext
spring.jpa.properties.hibernate.id.new_generator_mappings=true
spring.jpa.hibernate.ddl-auto=update
Tạo entity
Base entity
@Getter
@Setter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class BaseEntity implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private boolean deleted = false;
@CreatedDate
private Date createdAt;
@LastModifiedDate
private Date updatedAt;
private Long createdBy;
private Long updatedBy;
}
- Để sử dụng được 2 annotations
@CreatedDate
và@LastModifiedDate
, ngoài thêm@EntityListeners(AuditingEntityListener.class)
thì ở class Application (class chứa main để run app spring) thêm@EnableJpaAuditing
. - Còn
@Getter@Setter
mình dùng của thử viện lombok, nếu ide của bạn báo lỗi thì hãy thêm plugin lombok vào hoặc bạn có thể tạo getter, setter như bình thường.
User
@Entity
@Table(name = "t_user")
@Getter
@Setter
public class User extends BaseEntity {
private String username;
private String password;
@OneToMany(cascade = CascadeType.REFRESH, fetch = FetchType.EAGER)
@JoinTable(name = "t_user_role", joinColumns = {@JoinColumn(name = "user_id")}, inverseJoinColumns = {@JoinColumn(name = "role_id")})
private Set<Role> roles = new HashSet<>();
}
Role
@Entity
@Table(name = "t_role")
@Getter
@Setter
public class Role extends BaseEntity {
private String roleName;
private String roleKey;
@OneToMany(cascade = CascadeType.REFRESH, fetch = FetchType.EAGER)
@JoinTable(name = "t_role_permission", joinColumns = {@JoinColumn(name = "role_id")}, inverseJoinColumns = {@JoinColumn(name = "permission_id")})
private Set<Permission> permissions = new HashSet<>();
}
Permission
@Entity
@Table(name = "t_permission")
@Getter
@Setter
public class Permission extends BaseEntity {
private String permissionName;
private String permissionKey;
}
Token
@Entity
@Table(name = "t_token")
@Getter
@Setter
public class Token extends BaseEntity {
@Column(length = 1000)
private String token;
private Date tokenExpDate;
}
Chuẩn bị dữ liệu
- đây là dữ liệu mình chuẩn bị sẵn. Ở đây mình tạo ra 4 permissions(thêm, sửa, xóa, xem user). 2 roles(Supper User là role có full quyền, còn khách không có quyền gì cả). Một user với username là hunghh và password là 123456 có role ADMIN.
INSERT INTO `demo_springjwt`.`t_permission` (`permission_key`, `permission_name`) VALUES
('USER_CREATE', 'tạo user'), ('USER_READ','xem user'), ('USER_UPDATE', 'sửa user'), ('USER_DELETE', 'xóa user');
INSERT INTO `demo_springjwt`.`t_role` (`role_key`, `role_name`) VALUES
('ADMIN', 'Supper User'), ('CUSTOMER', 'Khách');
INSERT INTO `demo_springjwt`.`t_user` (`username`, `password`) VALUES
('hunghh', '$2a$10$VObHxmxycf0.QJNXlwqEc.mFZ.iYkS5V4zAJ0xdIMSoEYoW18O7cu');
INSERT INTO `demo_springjwt`.`t_role_permission` (`role_id`, `permission_id`) VALUES
(1, 1), (1, 2), (1, 3), (1, 4);
INSERT INTO `demo_springjwt`.`t_user_role` (`user_id`, `role_id`) VALUES
(1, 1);
Giải thích chút chỗ phân quyền của mình
- Ở đây ý đồ mình đang là 1 role có thể có nhiều permission và một user có thể có nhiều role khác nhau
Tạo thử api đăng ký
UserRepository
public interface UserRepository extends JpaRepository<User, Long> {
}
UserService
public interface UserService {
User createUser(User user);
}
UserServiceImpl
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserRepository userRepository;
@Override
public User createUser(User user) {
return userRepository.saveAndFlush(user);
}
}
AuthController
@RestController
public class AuthController {
@Autowired
private UserService userService;
@PostMapping("/register")
public User register(@RequestBody User user){
user.setPassword(new BCryptPasswordEncoder().encode(user.getPassword()));
return userService.createUser(user);
}
}
Bỏ kiểm tra với register
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests().antMatchers("/register").permitAll();
}
}
Test thử
kết quả
những phần chưa có thông tin ta sẽ xử lý ở những phần sau
Phần tiếp theo
- Ở phần kế tiếp mình sẽ hướng dẫn cách tạo ra JWT và làm thêm cái API đăng nhập ạ. cảm ơn mọi người đã đọc ạ
Phần 2: https://kipalog.com/posts/Spring-Security---JWT--Phan-2---Tao-JWT-va-lam-cai-api-login
Phần 3: https://kipalog.com/posts/Spring-Security---JWT--Phan-3---Doc-JWT-va-lam-mot-vai-api-test-permission






