feat:权限v1
This commit is contained in:
@@ -1,4 +1,19 @@
|
||||
package com.xiang.xservice.auth.api.api;
|
||||
|
||||
|
||||
import com.xiang.xservice.auth.api.dto.req.LoginRequest;
|
||||
import com.xiang.xservice.auth.api.dto.req.RegisterRequest;
|
||||
import com.xiang.xservice.auth.api.dto.resp.LoginResp;
|
||||
import com.xiang.xservice.auth.api.dto.resp.RegisterResp;
|
||||
import com.xiang.xservice.basic.common.resp.Result;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
public interface TokenApi {
|
||||
|
||||
Result<LoginResp> login(@RequestBody @NotNull(message = "请求参数不能为空") @Valid LoginRequest request);
|
||||
|
||||
Result<RegisterResp> register(@RequestBody @Valid @NotNull(message = "请求参数不能为空") RegisterRequest request);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import lombok.Getter;
|
||||
public enum Code02RoleErrorCode implements BaseErrorCode {
|
||||
|
||||
ROLE_NOT_EXISTS("A1000201", "角色不存在"),
|
||||
USER_ROLE_NOT_EXISTS("A1000202", "用户角色权限不存在!")
|
||||
;
|
||||
|
||||
private final String code;
|
||||
|
||||
@@ -5,12 +5,23 @@ import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class LoginRequest {
|
||||
|
||||
@NotBlank(message = "用户名不能为空")
|
||||
private String username;
|
||||
|
||||
@NotBlank(message = "密码不能为空")
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* todo 目前只支持用户名密码登录
|
||||
* 1. 用户名密码登录
|
||||
* 2. 手机号密码登录
|
||||
* 3. 邮箱密码登录
|
||||
*/
|
||||
private Integer loginType;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.xiang.xservice.auth.server.controller;
|
||||
|
||||
import com.xiang.xservice.auth.api.api.TokenApi;
|
||||
import com.xiang.xservice.auth.api.dto.req.LoginRequest;
|
||||
import com.xiang.xservice.auth.api.dto.req.RegisterRequest;
|
||||
import com.xiang.xservice.auth.api.dto.resp.LoginResp;
|
||||
@@ -20,7 +21,7 @@ import java.util.Objects;
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
public class TokenController {
|
||||
public class TokenController implements TokenApi {
|
||||
|
||||
private final XUserService userService;
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import com.xiang.xservice.basic.common.resp.Result;
|
||||
import com.xiang.xservice.basic.exception.BusinessException;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
@@ -31,7 +32,6 @@ public class UserController {
|
||||
|
||||
private final XUserService userService;
|
||||
|
||||
|
||||
@PostMapping("/private/user/list")
|
||||
public Result<UserResp> getUserList(@RequestBody @Valid @NotNull(message = "请求参数不能为空") UserQueryRequest request) {
|
||||
return Result.success(userService.getUserList(request));
|
||||
|
||||
@@ -4,6 +4,8 @@ import com.nimbusds.jose.jwk.JWKSet;
|
||||
import com.nimbusds.jose.jwk.RSAKey;
|
||||
import com.nimbusds.jose.jwk.source.JWKSource;
|
||||
import com.nimbusds.jose.proc.SecurityContext;
|
||||
import com.xiang.xservice.basic.exception.CustomAccessDeniedHandler;
|
||||
import com.xiang.xservice.basic.exception.CustomAuthenticationEntryPoint;
|
||||
import com.xiang.xservice.basic.utils.JwkUtils;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
@@ -21,6 +23,7 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
|
||||
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
||||
import org.springframework.security.oauth2.jwt.JwtEncoder;
|
||||
import org.springframework.security.oauth2.jwt.NimbusJwtEncoder;
|
||||
import org.springframework.security.oauth2.server.authorization.client.JdbcRegisteredClientRepository;
|
||||
@@ -45,6 +48,8 @@ public class AuthorizationServerConfig {
|
||||
@Value("${user.auth.redirectUrl}")
|
||||
private String redirectUrl;
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
private final CustomAuthenticationEntryPoint customAuthenticationEntryPoint;
|
||||
private final CustomAccessDeniedHandler customAccessDeniedHandler;
|
||||
|
||||
@Bean
|
||||
@Order(1)
|
||||
@@ -62,9 +67,20 @@ public class AuthorizationServerConfig {
|
||||
.authorizeRequests(authorizeRequests -> authorizeRequests
|
||||
.antMatchers("/public/**").permitAll()
|
||||
.antMatchers("/open/**").permitAll()
|
||||
.antMatchers("/private/**").authenticated()
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
|
||||
.exceptionHandling(exception ->
|
||||
exception
|
||||
.authenticationEntryPoint(customAuthenticationEntryPoint)
|
||||
.accessDeniedHandler(customAccessDeniedHandler))
|
||||
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
||||
.oauth2ResourceServer(oauth ->
|
||||
oauth
|
||||
.jwt()
|
||||
.and()
|
||||
.authenticationEntryPoint(customAuthenticationEntryPoint)
|
||||
.accessDeniedHandler(customAccessDeniedHandler));
|
||||
return http.build();
|
||||
}
|
||||
|
||||
@@ -131,5 +147,10 @@ public class AuthorizationServerConfig {
|
||||
.issuer(issuer)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
|
||||
return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,4 +18,6 @@ public interface XUserRoleMapper {
|
||||
int delByRoleIds(@Param("list") List<Long> roleIds);
|
||||
|
||||
int addBatch(List<XUserRole> list);
|
||||
|
||||
List<XUserRole> getByUserId(@Param("userId") Long userId);
|
||||
}
|
||||
|
||||
@@ -1,13 +1,21 @@
|
||||
package com.xiang.xservice.auth.service.service;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.xiang.xservice.auth.service.entity.XRole;
|
||||
import com.xiang.xservice.auth.service.entity.XUser;
|
||||
import com.xiang.xservice.auth.service.entity.XUserRole;
|
||||
import com.xiang.xservice.auth.service.repository.mapper.XRoleMapper;
|
||||
import com.xiang.xservice.auth.service.repository.mapper.XUserMapper;
|
||||
import com.xiang.xservice.auth.service.repository.mapper.XUserRoleMapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@Service
|
||||
@@ -15,6 +23,8 @@ import java.util.Objects;
|
||||
public class CustomUserDetailsService implements UserDetailsService {
|
||||
|
||||
private final XUserMapper userMapper;
|
||||
private final XRoleMapper roleMapper;
|
||||
private final XUserRoleMapper userRoleMapper;
|
||||
|
||||
@Override
|
||||
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||
@@ -22,11 +32,17 @@ public class CustomUserDetailsService implements UserDetailsService {
|
||||
if (Objects.isNull(user)) {
|
||||
throw new RuntimeException("用户不存在!");
|
||||
}
|
||||
|
||||
List<XUserRole> userRoles = userRoleMapper.getByUserId(user.getId());
|
||||
List<Long> roleIds = userRoles.stream().map(XUserRole::getRoleId).toList();
|
||||
List<SimpleGrantedAuthority> grantedAuthorities = Lists.newArrayList();
|
||||
if (CollectionUtils.isNotEmpty(roleIds)) {
|
||||
List<XRole> roles = roleMapper.getRoleByIds(roleIds);
|
||||
grantedAuthorities.addAll(roles.stream().map(role -> new SimpleGrantedAuthority("ROLE_" + role.getCode())).toList());
|
||||
}
|
||||
return org.springframework.security.core.userdetails.User
|
||||
.withUsername(user.getUsername())
|
||||
.password(user.getPassword()) // 已经加密的
|
||||
.authorities("admin")
|
||||
.authorities(grantedAuthorities)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.xiang.xservice.auth.service.service.impl;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.xiang.xservice.auth.api.code.Code01UserErrorCode;
|
||||
import com.xiang.xservice.auth.api.code.Code02RoleErrorCode;
|
||||
import com.xiang.xservice.auth.api.dto.req.LoginRequest;
|
||||
import com.xiang.xservice.auth.api.dto.req.RegisterRequest;
|
||||
import com.xiang.xservice.auth.api.dto.req.user.UserAddRequest;
|
||||
@@ -13,6 +14,7 @@ import com.xiang.xservice.auth.api.dto.resp.LoginResp;
|
||||
import com.xiang.xservice.auth.api.dto.resp.RegisterResp;
|
||||
import com.xiang.xservice.auth.api.dto.resp.UserResp;
|
||||
import com.xiang.xservice.auth.service.convert.XUserConvert;
|
||||
import com.xiang.xservice.auth.service.entity.XRole;
|
||||
import com.xiang.xservice.auth.service.entity.XUser;
|
||||
import com.xiang.xservice.auth.service.entity.XUserRole;
|
||||
import com.xiang.xservice.auth.service.enums.UserStatusEnum;
|
||||
@@ -22,6 +24,7 @@ import com.xiang.xservice.auth.service.repository.mapper.XUserRoleMapper;
|
||||
import com.xiang.xservice.auth.service.service.XUserService;
|
||||
import com.xiang.xservice.basic.enums.DelStatusEnum;
|
||||
import com.xiang.xservice.basic.exception.BusinessException;
|
||||
import com.xiang.xservice.basic.utils.JsonUtils;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
@@ -41,6 +44,7 @@ import java.time.LocalDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@@ -67,16 +71,30 @@ public class XUserServiceImpl implements XUserService {
|
||||
throw new BusinessException(e.getMessage());
|
||||
}
|
||||
|
||||
XUser user = userMapper.selectByUsername(request.getUsername());
|
||||
if (Objects.isNull(user)) {
|
||||
throw new BusinessException(Code01UserErrorCode.USER_NOT_EXISTS);
|
||||
}
|
||||
List<String> roleCodes = Lists.newArrayList();
|
||||
List<XUserRole> userRoles = userRoleMapper.getByUserId(user.getId());
|
||||
if (CollectionUtils.isNotEmpty(userRoles)) {
|
||||
List<XRole> roles = roleMapper.getRoleByIds(userRoles.stream().map(XUserRole::getRoleId).collect(Collectors.toList()));
|
||||
if (CollectionUtils.isEmpty(roles)) {
|
||||
throw new BusinessException(Code02RoleErrorCode.ROLE_NOT_EXISTS);
|
||||
}
|
||||
roleCodes.addAll(roles.stream().map(XRole::getCode).toList());
|
||||
}
|
||||
// 生成 token
|
||||
Instant now = Instant.now();
|
||||
|
||||
// todo 1. 构建 claims
|
||||
JwtClaimsSet claims = JwtClaimsSet.builder()
|
||||
// 对应 ProviderSettings.issuer
|
||||
.issuedAt(now)
|
||||
.expiresAt(now.plus(1, ChronoUnit.HOURS))
|
||||
.expiresAt(now.plus(3, ChronoUnit.HOURS))
|
||||
// 自定义 scope
|
||||
.claim("timestamp", System.currentTimeMillis())
|
||||
.claim("username", request.getUsername())
|
||||
.claim("roles", JsonUtils.toJsonString(roleCodes))
|
||||
.build();
|
||||
|
||||
// 2. 编码生成 token
|
||||
|
||||
@@ -38,5 +38,10 @@
|
||||
</foreach>
|
||||
</insert>
|
||||
|
||||
<select id="getByUserId" resultMap="BaseResultMap">
|
||||
select <include refid="Base_Column_List"/>
|
||||
from x_user_role
|
||||
where user_id = #{userId}
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
Reference in New Issue
Block a user