Skip to content

Commit

Permalink
feat: Add operation logs (#30)
Browse files Browse the repository at this point in the history
* feat: add operation logs
  • Loading branch information
gangb-tech authored Aug 31, 2022
1 parent b403c70 commit 8ed7ab5
Show file tree
Hide file tree
Showing 18 changed files with 191 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ public class GuestAuthenticationProcessingFilter extends AbstractAuthenticationP

private static final String GUEST_LOGIN_ACCOUNT_PARAM = "account";

private static final String ACCOUNT_SOURCE = "source";

protected GuestAuthenticationProcessingFilter() {
super(GUEST_LOGIN_PATH);
}
Expand All @@ -34,7 +36,8 @@ public Authentication attemptAuthentication(HttpServletRequest request, HttpServ
String body = IOUtils.toString(is, StandardCharsets.UTF_8);
Map<String, String> authParam = mapper.readValue(body, Map.class);
String account = authParam.get(GUEST_LOGIN_ACCOUNT_PARAM);
return getAuthenticationManager().authenticate(new GuestAuthenticationToken(account, ""));
String source = authParam.get(ACCOUNT_SOURCE);
return getAuthenticationManager().authenticate(new GuestAuthenticationToken(account, source, ""));
}

}
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package com.featureprobe.api.auth;

import com.featureprobe.api.base.enums.OperationType;
import com.featureprobe.api.entity.Member;
import com.featureprobe.api.entity.OperationLog;
import com.featureprobe.api.service.GuestService;
import com.featureprobe.api.service.MemberService;
import com.featureprobe.api.service.OperationLogService;
import lombok.AllArgsConstructor;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
Expand All @@ -21,16 +24,22 @@ public class GuestAuthenticationProvider implements AuthenticationProvider {

private GuestService guestService;

private OperationLogService operationLogService;

@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
GuestAuthenticationToken token = (GuestAuthenticationToken) authentication;
Optional<Member> member = memberService.findByAccount(token.getAccount());
OperationLog log = new OperationLog(OperationType.LOGIN.name() + "_" + token.getSource(),
token.getAccount());
if (member.isPresent()) {
memberService.updateVisitedTime(token.getAccount());
operationLogService.save(log);
return new UserPasswordAuthenticationToken(member.get(),
Arrays.asList(new SimpleGrantedAuthority(member.get().getRole().name())));
} else {
Member newMember = guestService.initGuest(token.getAccount());
Member newMember = guestService.initGuest(token.getAccount(), token.getSource());
operationLogService.save(log);
return new UserPasswordAuthenticationToken(newMember,
Arrays.asList(new SimpleGrantedAuthority(newMember.getRole().name())));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,16 @@ public class GuestAuthenticationToken extends AbstractAuthenticationToken {

private String account;

private String source;

private String password;

private Member principal;

public GuestAuthenticationToken(String account, String password) {
public GuestAuthenticationToken(String account, String source, String password) {
super(null);
this.account = account;
this.source = source;
this.password = password;
super.setAuthenticated(false);
}
Expand Down Expand Up @@ -46,11 +49,14 @@ public String getAccount() {
return account;
}

public String getSource() {
return source;
}

public String getPassword() {
return password;
}


public String getRole() {
if (principal == null) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ public class UserPasswordAuthenticationProcessingFilter extends AbstractAuthenti

private static final String GUEST_LOGIN_ACCOUNT_PARAM = "account";

private static final String ACCOUNT_SOURCE = "source";

private static final String GUEST_LOGIN_PASSWORD_PARAM = "password";

protected UserPasswordAuthenticationProcessingFilter() {
Expand All @@ -35,7 +37,8 @@ public Authentication attemptAuthentication(HttpServletRequest request, HttpServ
String body = IOUtils.toString(is, StandardCharsets.UTF_8);
Map<String, String> authParam = mapper.readValue(body, Map.class);
String account = authParam.get(GUEST_LOGIN_ACCOUNT_PARAM);
String source = authParam.get(ACCOUNT_SOURCE);
String password = authParam.get(GUEST_LOGIN_PASSWORD_PARAM);
return getAuthenticationManager().authenticate(new UserPasswordAuthenticationToken(account, password));
return getAuthenticationManager().authenticate(new UserPasswordAuthenticationToken(account, source, password));
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package com.featureprobe.api.auth;

import com.featureprobe.api.base.enums.OperationType;
import com.featureprobe.api.entity.Member;
import com.featureprobe.api.entity.OperationLog;
import com.featureprobe.api.service.MemberService;
import com.featureprobe.api.service.OperationLogService;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.authentication.AuthenticationProvider;
Expand All @@ -19,14 +22,19 @@ public class UserPasswordAuthenticationProvider implements AuthenticationProvide

private MemberService memberService;

private OperationLogService operationLogService;

@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
UserPasswordAuthenticationToken token = (UserPasswordAuthenticationToken) authentication;
if (StringUtils.isNotBlank(token.getAccount()) && StringUtils.isNotBlank(token.getPassword())) {
Optional<Member> member = memberService.findByAccount(token.getAccount());
OperationLog log = new OperationLog(OperationType.LOGIN.name() + "_" + token.getSource(),
token.getAccount());
if (member.isPresent()
&& new BCryptPasswordEncoder().matches(token.getPassword(), member.get().getPassword())) {
memberService.updateVisitedTime(token.getAccount());
operationLogService.save(log);
return new UserPasswordAuthenticationToken(member.get(),
Arrays.asList(new SimpleGrantedAuthority(member.get().getRole().name())));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,16 @@ public class UserPasswordAuthenticationToken extends AbstractAuthenticationToken

private String account;

private String source;

private String password;

private Member principal;

public UserPasswordAuthenticationToken(String account, String password) {
public UserPasswordAuthenticationToken(String account, String source, String password) {
super(null);
this.account = account;
this.source = source;
this.password = password;
super.setAuthenticated(false);
}
Expand Down Expand Up @@ -46,11 +49,14 @@ public String getAccount() {
return account;
}

public String getSource() {
return source;
}

public String getPassword() {
return password;
}


public String getRole() {
if (principal == null) {
return null;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.featureprobe.api.base.enums;

public enum OperationType {
LOGIN
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ public class MemberCreateRequest {
@NotNull
private List<String> accounts;

private String source;

@NotBlank
private String password;

Expand Down
2 changes: 2 additions & 0 deletions src/main/java/com/featureprobe/api/entity/Member.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ public class Member extends AbstractAuditEntity implements AuthenticatedPrincipa
@Column(columnDefinition = "TINYINT")
private Boolean deleted;

private String source;

@ManyToMany(cascade = CascadeType.PERSIST, fetch = FetchType.LAZY)
@JoinTable(name = "organization_member", joinColumns = @JoinColumn(name = "member_id"),
inverseJoinColumns = @JoinColumn(name = "organization_id"))
Expand Down
53 changes: 53 additions & 0 deletions src/main/java/com/featureprobe/api/entity/OperationLog.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.featureprobe.api.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.hibernate.annotations.DynamicInsert;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import java.util.Date;

@EqualsAndHashCode
@NoArgsConstructor
@AllArgsConstructor
@Data
@Entity
@Table(name = "operation_logs")
@DynamicInsert
@ToString(callSuper = true)
public class OperationLog {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(name = "res_param")
private String response;

@Column(name = "req_param")
private String request;

private String type;

private String account;

@Temporal(TemporalType.TIMESTAMP)
@Column(name = "created_time")
private Date createdTime;

public OperationLog(String type, String account) {
this.type = type;
this.account = account;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.featureprobe.api.repository;

import com.featureprobe.api.entity.OperationLog;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;

@Repository
public interface OperationLogRepository extends JpaRepository<OperationLog, Long>,
JpaSpecificationExecutor<OperationLog> {
}
3 changes: 2 additions & 1 deletion src/main/java/com/featureprobe/api/service/GuestService.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,15 @@ public class GuestService {
private static final String DEMO_INIT_DATA_FILE_PATH = "db/demo_init_data.sql";

@Transactional(rollbackFor = Exception.class)
public Member initGuest(String account) {
public Member initGuest(String account, String source) {
Member createdMember = new Member();
createdMember.setAccount(account);
createdMember.setPassword(passwordEncoder.encode(appConfig.getGuestDefaultPassword()));
createdMember.setRole(RoleEnum.ADMIN);
List<Organization> organizations = new ArrayList<>(1);
organizations.add(new Organization(account));
createdMember.setOrganizations(organizations);
createdMember.setSource(source);
Member savedMember = memberRepository.save(createdMember);
SecurityContextHolder.setContext(new SecurityContextImpl(new JwtAuthenticationToken(Jwt.withTokenValue("_")
.claim("userId", savedMember.getId()).claim("account", savedMember.getAccount())
Expand Down
8 changes: 6 additions & 2 deletions src/main/java/com/featureprobe/api/service/MemberService.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ public class MemberService {
@PersistenceContext
public EntityManager entityManager;

private static final String API_CREATE_MEMBER_SOURCE = "INTERNAL";

private static final PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

@Transactional(rollbackFor = Exception.class)
Expand Down Expand Up @@ -109,12 +111,14 @@ private List<Member> newNumbers(MemberCreateRequest createRequest) {
return createRequest.getAccounts()
.stream()
.filter(account -> memberIncludeDeletedService.validateAccountIncludeDeleted(account))
.map(account -> newMember(account, createRequest.getPassword())).collect(Collectors.toList());
.map(account -> newMember(account, createRequest.getSource(), createRequest.getPassword()))
.collect(Collectors.toList());
}

private Member newMember(String account, String password) {
private Member newMember(String account, String source, String password) {
Member member = new Member();
member.setAccount(account);
member.setSource(source);
member.setRole(RoleEnum.MEMBER);
member.setPassword(new BCryptPasswordEncoder().encode(password));
Organization organization = organizationRepository.findById(TenantContext.getCurrentOrganization()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.featureprobe.api.service;

import com.featureprobe.api.entity.OperationLog;
import com.featureprobe.api.repository.OperationLogRepository;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

@Slf4j
@Service
@AllArgsConstructor
public class OperationLogService {

private OperationLogRepository operationLogRepository;

public void save(OperationLog log) {
operationLogRepository.save(log);
}

}
12 changes: 12 additions & 0 deletions src/main/resources/db/migration/V29__add_member_source_fields.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
alter table member add source VARCHAR(256) default '' not null after deleted;

create table operation_logs
(
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`res_param` text,
`req_param` text,
`type` varchar(64) NOT NULL DEFAULT '',
`account` varchar(128) NOT NULL DEFAULT '',
`created_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
)ENGINE=InnoDB collate = utf8mb4_unicode_ci;
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class GuestServiceSpec extends Specification{
given:
Query query = Mock(NativeQueryImplementor)
when:
def guest = guestService.initGuest("Admin")
def guest = guestService.initGuest("Admin", "test")
then:
1 * memberRepository.save(_) >> new Member(id: 1, account: "Admin", role: RoleEnum.ADMIN, organizations: [new Organization(id: 1)])
1 * projectRepository.count() >> 2
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.featureprobe.api.service

import com.featureprobe.api.entity.OperationLog
import com.featureprobe.api.repository.OperationLogRepository
import spock.lang.Specification

class OperationLogServiceSpec extends Specification{

OperationLogRepository operationLogRepository

OperationLogService operationLogService

def setup() {
operationLogRepository = Mock(OperationLogRepository)
operationLogService = new OperationLogService(operationLogRepository)
}

def "saved operation log"() {
when:
operationLogService.save(new OperationLog("test", "Admin"))
then:
1 * operationLogRepository.save(_)
}
}

Loading

0 comments on commit 8ed7ab5

Please sign in to comment.