diff --git a/pom.xml b/pom.xml index ab68f9a..68fdafb 100644 --- a/pom.xml +++ b/pom.xml @@ -78,6 +78,16 @@ org.springframework.boot spring-boot-starter-security + + io.jsonwebtoken + jjwt + 0.9.1 + + + org.springframework.security + spring-security-web + + diff --git a/src/main/java/com/waterquality/projectmanagement/config/JwtAuthenticationFilter.java b/src/main/java/com/waterquality/projectmanagement/config/JwtAuthenticationFilter.java new file mode 100644 index 0000000..69ab391 --- /dev/null +++ b/src/main/java/com/waterquality/projectmanagement/config/JwtAuthenticationFilter.java @@ -0,0 +1,49 @@ +package com.waterquality.projectmanagement.config; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.filter.OncePerRequestFilter; + +import java.io.IOException; + +@RequiredArgsConstructor +public class JwtAuthenticationFilter extends OncePerRequestFilter { + + private final JwtTokenProvider jwtTokenProvider; + + @Override + protected void doFilterInternal( + HttpServletRequest request, + HttpServletResponse response, + FilterChain filterChain + ) throws ServletException, IOException { + // 1. 从请求头中获取 JWT Token + String token = resolveToken(request); + + // 2. 验证 Token 是否有效 + if (token != null && jwtTokenProvider.validateToken(token)) { + // 3. 如果 Token 有效,获取认证信息 + Authentication authentication = jwtTokenProvider.getAuthentication(token); + + // 4. 将认证信息设置到 SecurityContext 中 + SecurityContextHolder.getContext().setAuthentication(authentication); + } + + // 5. 继续执行过滤器链 + filterChain.doFilter(request, response); + } + + // 从请求头中解析 JWT Token + private String resolveToken(HttpServletRequest request) { + String bearerToken = request.getHeader("Authorization"); + if (bearerToken != null && bearerToken.startsWith("Bearer ")) { + return bearerToken.substring(7); + } + return null; + } +} \ No newline at end of file diff --git a/src/main/java/com/waterquality/projectmanagement/config/JwtConfigurer.java b/src/main/java/com/waterquality/projectmanagement/config/JwtConfigurer.java new file mode 100644 index 0000000..fd2157e --- /dev/null +++ b/src/main/java/com/waterquality/projectmanagement/config/JwtConfigurer.java @@ -0,0 +1,21 @@ +package com.waterquality.projectmanagement.config; + +import org.springframework.security.config.annotation.SecurityConfigurerAdapter; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.web.DefaultSecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + +public class JwtConfigurer extends SecurityConfigurerAdapter { + + private final JwtTokenProvider jwtTokenProvider; + + public JwtConfigurer(JwtTokenProvider jwtTokenProvider) { + this.jwtTokenProvider = jwtTokenProvider; + } + + @Override + public void configure(HttpSecurity http) { + JwtTokenFilter customFilter = new JwtTokenFilter(jwtTokenProvider); + http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class); + } +} \ No newline at end of file diff --git a/src/main/java/com/waterquality/projectmanagement/config/JwtTokenFilter.java b/src/main/java/com/waterquality/projectmanagement/config/JwtTokenFilter.java new file mode 100644 index 0000000..9ed0e34 --- /dev/null +++ b/src/main/java/com/waterquality/projectmanagement/config/JwtTokenFilter.java @@ -0,0 +1,40 @@ +package com.waterquality.projectmanagement.config; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.filter.OncePerRequestFilter; + +import java.io.IOException; + +public class JwtTokenFilter extends OncePerRequestFilter { + + private final JwtTokenProvider jwtTokenProvider; + + public JwtTokenFilter(JwtTokenProvider jwtTokenProvider) { + this.jwtTokenProvider = jwtTokenProvider; + } + + @Override + protected void doFilterInternal(HttpServletRequest request, + HttpServletResponse response, + FilterChain filterChain) throws ServletException, IOException { + String token = resolveToken(request); + if (token != null && jwtTokenProvider.validateToken(token)) { + Authentication auth = jwtTokenProvider.getAuthentication(token); + SecurityContextHolder.getContext().setAuthentication(auth); + } + filterChain.doFilter(request, response); + } + + private String resolveToken(HttpServletRequest req) { + String bearerToken = req.getHeader("Authorization"); + if (bearerToken != null && bearerToken.startsWith("Bearer ")) { + return bearerToken.substring(7); + } + return null; + } +} \ No newline at end of file diff --git a/src/main/java/com/waterquality/projectmanagement/config/JwtTokenProvider.java b/src/main/java/com/waterquality/projectmanagement/config/JwtTokenProvider.java new file mode 100644 index 0000000..a0cea7a --- /dev/null +++ b/src/main/java/com/waterquality/projectmanagement/config/JwtTokenProvider.java @@ -0,0 +1,74 @@ +package com.waterquality.projectmanagement.config; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import org.springframework.beans.factory.annotation.Value; // 确保导入这个 +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.stereotype.Component; +import com.waterquality.projectmanagement.repository.EmployeeRepository; // 确保正确导入你的 EmployeeRepository + +import java.util.Date; +import java.util.stream.Collectors; + +@Component +public class JwtTokenProvider { + + @Value("${jwt.secret}") + private String secret; + + @Value("${jwt.expiration}") + private long validityInMilliseconds; + + @Autowired + private EmployeeRepository employeeRepository; // 添加 EmployeeRepository 的依赖注入 + + public String createToken(UserDetails userDetails) { + Claims claims = Jwts.claims().setSubject(userDetails.getUsername()); + claims.put("roles", userDetails.getAuthorities().stream() + .map(GrantedAuthority::getAuthority) + .collect(Collectors.toList())); + + Date now = new Date(); + Date validity = new Date(now.getTime() + validityInMilliseconds); + + return Jwts.builder() + .setClaims(claims) + .setIssuedAt(now) + .setExpiration(validity) + .signWith(SignatureAlgorithm.HS256, secret) + .compact(); + } + + public Authentication getAuthentication(String token) { + UserDetails userDetails = (UserDetails) employeeRepository.findByUsername(getUsername(token)) + .orElseThrow(() -> new UsernameNotFoundException("用户不存在")); + return new UsernamePasswordAuthenticationToken(userDetails, "", userDetails.getAuthorities()); + } + + private String getUsername(String token) { + return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody().getSubject(); + } + + public boolean validateToken(String token) { + try { + Jwts.parser().setSigningKey(secret).parseClaimsJws(token); + return true; // 验证成功 + } catch (io.jsonwebtoken.ExpiredJwtException e) { + // 处理过期的令牌 + return false; + } catch (io.jsonwebtoken.SignatureException e) { + // 处理签名异常 + return false; + } catch (Exception e) { + // 处理其他异常 + return false; + } + } + // 其他验证方法... +} \ No newline at end of file diff --git a/src/main/java/com/waterquality/projectmanagement/config/SecurityConfig.java b/src/main/java/com/waterquality/projectmanagement/config/SecurityConfig.java new file mode 100644 index 0000000..41f8121 --- /dev/null +++ b/src/main/java/com/waterquality/projectmanagement/config/SecurityConfig.java @@ -0,0 +1,70 @@ +package com.waterquality.projectmanagement.config; + +import com.waterquality.projectmanagement.repository.EmployeeRepository; +import jakarta.servlet.Filter; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.AuthenticationProvider; +import org.springframework.security.authentication.dao.DaoAuthenticationProvider; +import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; +import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.http.SessionCreationPolicy; +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.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + +@Configuration +@EnableWebSecurity +@EnableMethodSecurity(prePostEnabled = true) +@RequiredArgsConstructor +public class SecurityConfig { + + private final EmployeeRepository employeeRepository; + private final JwtTokenProvider jwtTokenProvider; + + @Bean + public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + http + .csrf(csrf -> csrf.disable()) + .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) + .authorizeHttpRequests(authz -> authz + .requestMatchers("/api/auth/**").permitAll() + .anyRequest().authenticated()) + .authenticationProvider(authenticationProvider()) + .addFilterBefore((Filter) new JwtAuthenticationFilter(jwtTokenProvider), UsernamePasswordAuthenticationFilter.class); + + return http.build(); + } + + @Bean + public UserDetailsService userDetailsService() { + return username -> (UserDetails) employeeRepository.findByUsername(username) + .orElseThrow(() -> new UsernameNotFoundException("用户不存在")); + } + + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } + + @Bean + public AuthenticationProvider authenticationProvider() { + DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider(); + authProvider.setUserDetailsService(userDetailsService()); + authProvider.setPasswordEncoder(passwordEncoder()); + return authProvider; + } + + @Bean + public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception { + return config.getAuthenticationManager(); + } +} \ No newline at end of file diff --git a/src/main/java/com/waterquality/projectmanagement/controller/AuthController.java b/src/main/java/com/waterquality/projectmanagement/controller/AuthController.java new file mode 100644 index 0000000..10f0306 --- /dev/null +++ b/src/main/java/com/waterquality/projectmanagement/controller/AuthController.java @@ -0,0 +1,70 @@ +package com.waterquality.projectmanagement.controller; + +// 明文密码,请注意 + +import com.waterquality.projectmanagement.config.JwtTokenProvider; +import com.waterquality.projectmanagement.dto.login.AuthResponse; +import com.waterquality.projectmanagement.dto.login.LoginDTO; +import com.waterquality.projectmanagement.entity.employee.Employee; +import com.waterquality.projectmanagement.repository.EmployeeRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.AuthenticationException; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.validation.Valid; + +@RestController +@RequestMapping("/api/auth") +@RequiredArgsConstructor +@Slf4j +public class AuthController { + + private final AuthenticationManager authenticationManager; + private final JwtTokenProvider jwtTokenProvider; + private final EmployeeRepository employeeRepository; + + @PostMapping("/login") + public ResponseEntity login(@Valid @RequestBody LoginDTO dto) { + try { + // 查找用户 + Employee employee = (Employee) employeeRepository.findByUsername(dto.getUsername()) + .orElseThrow(() -> new BadCredentialsException("用户不存在")); + + // 检查密码是否匹配 + if (!employee.getPassword().equals(dto.getPassword())) { + log.error("登录失败 - 无效凭证: {},原因: Bad credentials", dto.getUsername()); + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("用户名或密码错误"); + } + + // 检查账号状态(可选) + if (!employee.isEnabled()) { + log.warn("尝试登录的账号已被禁用: {}", dto.getUsername()); + return ResponseEntity.status(HttpStatus.FORBIDDEN).body("账号已被禁用"); + } + + // 生成token + String token = jwtTokenProvider.createToken(employee); + + // 返回认证响应 + return ResponseEntity.ok(new AuthResponse( + token, + employee.getEmployeeId(), + employee.getName(), + employee.getPosition().name() + )); + + } catch (Exception e) { + log.error("登录过程中发生未知错误,用户: {},异常信息: {}", dto.getUsername(), e.getMessage(), e); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("系统错误"); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/waterquality/projectmanagement/controller/c.java b/src/main/java/com/waterquality/projectmanagement/controller/WorkOrderController.java similarity index 80% rename from src/main/java/com/waterquality/projectmanagement/controller/c.java rename to src/main/java/com/waterquality/projectmanagement/controller/WorkOrderController.java index 576105e..498a0a0 100644 --- a/src/main/java/com/waterquality/projectmanagement/controller/c.java +++ b/src/main/java/com/waterquality/projectmanagement/controller/WorkOrderController.java @@ -2,10 +2,11 @@ package com.waterquality.projectmanagement.controller; import com.waterquality.projectmanagement.Response; import com.waterquality.projectmanagement.dto.order.*; +import com.waterquality.projectmanagement.entity.employee.CustomUserDetails; import com.waterquality.projectmanagement.entity.order.WorkOrderStatus; import com.waterquality.projectmanagement.service.WorkOrderService; -import lombok.*; -import org.apache.catalina.User; +import lombok.RequiredArgsConstructor; +import org.springframework.security.core.userdetails.UserDetails; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.web.PageableDefault; @@ -31,9 +32,10 @@ public class WorkOrderController { @PreAuthorize("hasRole('MAINTENANCE')") public ResponseEntity> createOrder( @Valid @RequestBody WorkOrderCreateDTO dto, - @AuthenticationPrincipal User user) { + @AuthenticationPrincipal UserDetails user) { + // 假设 UserDetails 实现了 getUsername() 方法返回用户 ID return ResponseEntity.ok(Response.newSuccess( - workOrderService.createOrder(dto, user.getId()))); + workOrderService.createOrder(dto, Integer.valueOf(user.getUsername())))); } @PatchMapping("/{id}/status") @@ -48,10 +50,10 @@ public class WorkOrderController { @GetMapping("/my-orders") public ResponseEntity>> getMyOrders( @RequestParam(required = false) Set statuses, - @AuthenticationPrincipal User user, + @AuthenticationPrincipal CustomUserDetails user, @PageableDefault Pageable pageable) { return ResponseEntity.ok(Response.newSuccess( - workOrderService.getOrdersByAssignee(user.getId(), + workOrderService.getOrdersByAssignee(user.getUserID(), statuses != null ? statuses : EnumSet.allOf(WorkOrderStatus.class), pageable))); } diff --git a/src/main/java/com/waterquality/projectmanagement/dto/EmployeeDTO.java b/src/main/java/com/waterquality/projectmanagement/dto/EmployeeDTO.java index 9b4801e..8fddea4 100644 --- a/src/main/java/com/waterquality/projectmanagement/dto/EmployeeDTO.java +++ b/src/main/java/com/waterquality/projectmanagement/dto/EmployeeDTO.java @@ -14,6 +14,8 @@ public class EmployeeDTO { private String contact_phone; private Status status; private Integer department; // 可以考虑使用简化的部门信息 + private String password; + private String username; // 可以根据需要添加其他字段 } \ No newline at end of file diff --git a/src/main/java/com/waterquality/projectmanagement/dto/login/AuthResponse.java b/src/main/java/com/waterquality/projectmanagement/dto/login/AuthResponse.java new file mode 100644 index 0000000..cef2ecc --- /dev/null +++ b/src/main/java/com/waterquality/projectmanagement/dto/login/AuthResponse.java @@ -0,0 +1,14 @@ +package com.waterquality.projectmanagement.dto.login; + +import lombok.AllArgsConstructor; +import lombok.Data; + +// AuthResponse.java +@Data +@AllArgsConstructor +public class AuthResponse { + private String token; + private Integer employeeId; + private String name; + private String position; +} diff --git a/src/main/java/com/waterquality/projectmanagement/dto/login/LoginDTO.java b/src/main/java/com/waterquality/projectmanagement/dto/login/LoginDTO.java new file mode 100644 index 0000000..765c45b --- /dev/null +++ b/src/main/java/com/waterquality/projectmanagement/dto/login/LoginDTO.java @@ -0,0 +1,16 @@ +package com.waterquality.projectmanagement.dto.login; + +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +// LoginDTO.java +@Data +public class LoginDTO { + @NotBlank(message = "用户名不能为空") + private String username; + + @NotBlank(message = "密码不能为空") + private String password; +} + diff --git a/src/main/java/com/waterquality/projectmanagement/dto/plan/InspectionPlanVO.java b/src/main/java/com/waterquality/projectmanagement/dto/plan/InspectionPlanVO.java index 1e089f4..b21ba60 100644 --- a/src/main/java/com/waterquality/projectmanagement/dto/plan/InspectionPlanVO.java +++ b/src/main/java/com/waterquality/projectmanagement/dto/plan/InspectionPlanVO.java @@ -9,7 +9,7 @@ import java.time.LocalDateTime; @Data public class InspectionPlanVO { private Integer planId; - private String employeeName; + private Integer employeeId; private String area; private LocalDateTime plannedTime; private PlanStatus status; diff --git a/src/main/java/com/waterquality/projectmanagement/entity/employee/CustomUserDetails.java b/src/main/java/com/waterquality/projectmanagement/entity/employee/CustomUserDetails.java new file mode 100644 index 0000000..76f026d --- /dev/null +++ b/src/main/java/com/waterquality/projectmanagement/entity/employee/CustomUserDetails.java @@ -0,0 +1,9 @@ +package com.waterquality.projectmanagement.entity.employee; + + +import org.springframework.security.core.userdetails.UserDetails; + +public interface CustomUserDetails extends UserDetails { + Integer getUserID(); + String getUsername(); +} \ No newline at end of file diff --git a/src/main/java/com/waterquality/projectmanagement/entity/employee/Employee.java b/src/main/java/com/waterquality/projectmanagement/entity/employee/Employee.java index 11fa603..5a97d19 100644 --- a/src/main/java/com/waterquality/projectmanagement/entity/employee/Employee.java +++ b/src/main/java/com/waterquality/projectmanagement/entity/employee/Employee.java @@ -3,17 +3,22 @@ package com.waterquality.projectmanagement.entity.employee; import com.waterquality.projectmanagement.entity.department.Department; import jakarta.persistence.*; import lombok.Data; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; + +import java.util.Collection; +import java.util.Collections; @Entity @Table(name = "employees") @Data -public class Employee { +public class Employee implements CustomUserDetails { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "employee_id") private Integer employeeId; - @Column(name = "employee_no",unique = true, nullable = false) + @Column(name = "employee_no", unique = true, nullable = false) private String employeeNo; private String name; @@ -31,6 +36,40 @@ public class Employee { @Column(name = "department_id") private Integer department; + // login + @Column(nullable = false, unique = true) + private String username; -} + @Column(nullable = false) + private String password; + + // 实现 UserDetails 接口方法 + @Override + public Collection getAuthorities() { + return Collections.singletonList(new SimpleGrantedAuthority("ROLE_" + position.name())); + } + + @Override + public boolean isAccountNonExpired() { return true; } + + @Override + public boolean isAccountNonLocked() { return true; } + + @Override + public boolean isCredentialsNonExpired() { return true; } + + @Override + public boolean isEnabled() { return status == Status.ACTIVE; } + + // 实现 getUserID 方法 + @Override + public Integer getUserID() { + return employeeId; + } + + @Override + public String getUsername() { + return name; // 返回用户名 + } +} \ No newline at end of file diff --git a/src/main/java/com/waterquality/projectmanagement/repository/EmployeeRepository.java b/src/main/java/com/waterquality/projectmanagement/repository/EmployeeRepository.java index cbb9764..f418727 100644 --- a/src/main/java/com/waterquality/projectmanagement/repository/EmployeeRepository.java +++ b/src/main/java/com/waterquality/projectmanagement/repository/EmployeeRepository.java @@ -14,10 +14,13 @@ public interface EmployeeRepository extends JpaRepository { // 根据工号查询 Optional findByEmployeeNo(String employeeNo); + Employee findEmployeeByEmployeeId(Integer employeeId); + // 按部门查询在职员工 List findByDepartmentAndStatus(Department department, Status status); Page findByDepartment(Department department, Pageable pageable); + Optional findByUsername(String username); } \ No newline at end of file diff --git a/src/main/java/com/waterquality/projectmanagement/service/EmployeeService.java b/src/main/java/com/waterquality/projectmanagement/service/EmployeeService.java index 53c1bad..d1598f6 100644 --- a/src/main/java/com/waterquality/projectmanagement/service/EmployeeService.java +++ b/src/main/java/com/waterquality/projectmanagement/service/EmployeeService.java @@ -25,6 +25,8 @@ public class EmployeeService { public Employee createEmployee(EmployeeDTO dto) { Employee employee = new Employee(); BeanUtils.copyProperties(dto, employee); + employee.setUsername(dto.getEmployeeNo()); + employee.setPassword("114514"); return employeeRepository.save(employee); } diff --git a/src/main/java/com/waterquality/projectmanagement/service/InspectionPlanService.java b/src/main/java/com/waterquality/projectmanagement/service/InspectionPlanService.java index 48168e1..38ea6da 100644 --- a/src/main/java/com/waterquality/projectmanagement/service/InspectionPlanService.java +++ b/src/main/java/com/waterquality/projectmanagement/service/InspectionPlanService.java @@ -43,7 +43,7 @@ public class InspectionPlanService { private InspectionPlanVO convertToVO(InspectionPlan plan) { InspectionPlanVO vo = new InspectionPlanVO(); vo.setPlanId(plan.getPlanId()); - vo.setEmployeeName(plan.getEmployee().getName()); + vo.setEmployeeId(plan.getEmployee().getEmployeeId()); vo.setArea(plan.getArea()); vo.setPlannedTime(plan.getPlannedTime()); vo.setStatus(plan.getStatus()); diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index f6a56f4..aaae883 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -5,7 +5,8 @@ spring.datasource.username=root spring.datasource.password=tju1895 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver - +jwt.secret=your_secret_key +jwt.expiration=3600000 server.port=8080 \ No newline at end of file