登陆代码优化,面向方法编程,优化ing
parent
0238e2960d
commit
407642d8b5
File diff suppressed because one or more lines are too long
|
@ -20,4 +20,7 @@ public class UserAccount {
|
|||
|
||||
@ApiModelProperty("密码/")
|
||||
private String password;
|
||||
|
||||
// @ApiModelProperty("uuid")
|
||||
// private String UUID;
|
||||
}
|
||||
|
|
|
@ -5,4 +5,7 @@ public class PermissionConstants {
|
|||
public static final String CODE_LIST = "codeList";
|
||||
public static final String ROLE = "role";
|
||||
public static final String PERMISSION_CODE = "permission_code";
|
||||
public static final String USER_CACHE_KEY = "user:username:";
|
||||
public static final String USER_KEY = "user:key:";
|
||||
public static final String USER_NAME = "username";
|
||||
}
|
||||
|
|
|
@ -3,7 +3,9 @@ package com.auth.server;
|
|||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
|
||||
@SpringBootApplication
|
||||
@MapperScan("com.auth.server.mapper")
|
||||
|
@ -15,4 +17,9 @@ public class EtlAuthServerApplication {
|
|||
SpringApplication.run(EtlAuthServerApplication.class, args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public BCryptPasswordEncoder encryptPasswordEncoder(){
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
//package com.auth.server.config;
|
||||
//import com.auth.server.interceptor.UserInterceptor;
|
||||
//import com.auth.server.mapper.UserMangeMapper;
|
||||
//import org.springframework.beans.factory.annotation.Autowired;
|
||||
//import org.springframework.context.annotation.Configuration;
|
||||
//import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
//import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
//@Configuration
|
||||
//public class MvcConfig implements WebMvcConfigurer {
|
||||
// @Autowired
|
||||
// private UserMangeMapper userMangeMapper;
|
||||
// @Override
|
||||
// public void addInterceptors(InterceptorRegistry registry) {
|
||||
// //添加拦截器,排除/路径和 /login路径
|
||||
// registry.addInterceptor(new UserInterceptor(userMangeMapper))
|
||||
// .excludePathPatterns("/","/user/login");
|
||||
// }
|
||||
//}
|
|
@ -1,13 +1,17 @@
|
|||
package com.auth.server.controller;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.nacos.api.model.v2.Result;
|
||||
import com.auth.common.entity.UserAccount;
|
||||
import com.auth.common.enums.PermissionConstants;
|
||||
import com.auth.server.service.UserManageService;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.etl.common.enums.ResponseCodeEnum;
|
||||
import com.etl.common.result.CommonResult;
|
||||
import com.etl.jwt.util.JwtTokenUtil;
|
||||
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
|
@ -16,10 +20,14 @@ import org.apache.shiro.mgt.DefaultSecurityManager;
|
|||
import org.apache.shiro.realm.SimpleAccountRealm;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 登录 controller层
|
||||
|
@ -33,49 +41,105 @@ public class LoginControler {
|
|||
private UserManageService userManageService;
|
||||
@Resource
|
||||
private JwtTokenUtil jwtTokenUtil;
|
||||
//用户登录(使用用户名)
|
||||
@PostMapping("/login")
|
||||
public Result<Object> UserLogin(@RequestBody UserAccount user)
|
||||
{
|
||||
String username=user.getUsername();
|
||||
String password=user.getPassword();
|
||||
|
||||
@Autowired
|
||||
private BCryptPasswordEncoder bCryptPasswordEncoder;
|
||||
|
||||
@Resource
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
/**
|
||||
* 用户登录 (使用用户名)
|
||||
* @param user
|
||||
* @return
|
||||
*/
|
||||
@ApiOperation(value = "用户登录")
|
||||
@ApiOperationSupport(author = "liz")
|
||||
@RequestMapping(value = "/login",method = RequestMethod.POST)
|
||||
public Result<Object> userLogin(@RequestBody UserAccount user) {
|
||||
// 获取用户名
|
||||
String username = user.getUsername();
|
||||
// 获取密码
|
||||
String password = user.getPassword();
|
||||
|
||||
// 参数校验
|
||||
Result result = checkUser(username, password);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
// 创建SimpleAccountRealm并添加账户信息
|
||||
SimpleAccountRealm simpleAccountRealm = new SimpleAccountRealm();
|
||||
// 确保这里添加的用户名和密码与用户提供的匹配
|
||||
simpleAccountRealm.addAccount(username, password, user.getRoles());
|
||||
|
||||
// 配置SecurityManager并设置Realm
|
||||
DefaultSecurityManager securityManager = new DefaultSecurityManager(simpleAccountRealm);
|
||||
// 设置SecurityManager
|
||||
SecurityUtils.setSecurityManager(securityManager);
|
||||
|
||||
//shiro验证
|
||||
Subject subject= SecurityUtils.getSubject();
|
||||
log.info("!11"+subject);
|
||||
Subject subject = SecurityUtils.getSubject();
|
||||
//根据用户名密码生成一个令牌
|
||||
AuthenticationToken token=new UsernamePasswordToken(username,password);
|
||||
|
||||
AuthenticationToken token = new UsernamePasswordToken(username, password);
|
||||
try {
|
||||
//执行登录操作
|
||||
// TODO 使用异步处理登录操作。在执行登录操作时,可以使用异步处理方式,避免阻塞主线程,提高系统性能。
|
||||
subject.login(token);
|
||||
//将用户信息存入redis
|
||||
saveUserInfoToRedis(username, user);
|
||||
} catch (UnknownAccountException e) {
|
||||
log.info("登录用户不存在:{}",e);
|
||||
return new Result<>(416,"用户不存在",username);
|
||||
log.info("登录用户不存在:{}", e);
|
||||
return new Result<>(416, "用户不存在", username);
|
||||
} catch (IncorrectCredentialsException e) {
|
||||
log.info("登录密码错误");
|
||||
return new Result<>(412,"密码错误,请重新登录",password);
|
||||
}catch (AuthenticationException e) {
|
||||
return new Result<>(412, "密码错误,请重新登录", password);
|
||||
} catch (AuthenticationException e) {
|
||||
log.warn("用户登录异常:" + e.getMessage());
|
||||
return new Result<>(416,"账户异常",username);
|
||||
return new Result<>(416, "账户异常", username);
|
||||
}
|
||||
//获取登录用户信息
|
||||
UserAccount account = userManageService.getOne(new QueryWrapper<UserAccount>().eq("username",username));
|
||||
// 通过 jwtTokenUtil 生成 JWT 令牌和刷新令牌
|
||||
Map<String, Object> tokenMap = jwtTokenUtil
|
||||
.generateTokenAndRefreshToken(String.valueOf(account.getId()), username);
|
||||
// 用户角色映射表中中查询用户角色
|
||||
userManageService.getOne(new QueryWrapper<UserAccount>().eq("username",username)).getRoles();
|
||||
return Result.success(tokenMap);
|
||||
UserAccount account = userManageService.getOne(new QueryWrapper<UserAccount>().eq(PermissionConstants.USER_NAME, username));
|
||||
// TODO 使用Redis等缓存技术将用户信息存储在内存中,当需要查询用户信息时先从缓存中获取,如果缓存中没有再查询数据库并将结果存入缓存
|
||||
saveAllUserInfoToRedis(account);
|
||||
// TODO 收集链接
|
||||
// TODO 对密码进行加密存储。将用户密码进行加密存储,可以避免明文密码泄露的风险,同时可以提高系统安全性
|
||||
// TODO 使用随机盐值:在每次加密时生成一个随机的盐值,并将其与密码一起进行加密。这样即使两个用户使用相同的密码,他们的加密结果也会不同,从而增加了破解的难度。
|
||||
// TODO 定期更新密码:要求用户定期更改密码,并强制要求新密码必须包含大写字母、小写字母、数字和特殊字符等元素,以提高密码复杂度。
|
||||
// TODO 限制登录尝试次数:限制用户在一定时间内只能尝试登录有限的次数,如果超过限制则锁定账户或延迟解锁时间,以防止暴力破解攻击
|
||||
// 密码加密 数据库密码跟输入密码做比对
|
||||
boolean matches = bCryptPasswordEncoder.matches(password, account.getPassword());
|
||||
if (matches){
|
||||
// 通过 jwtTokenUtil 生成 JWT 令牌和刷新令牌
|
||||
Map<String, Object> tokenMap = jwtTokenUtil
|
||||
.generateTokenAndRefreshToken(String.valueOf(account.getId()), username);
|
||||
// 用户角色映射表中中查询用户角色
|
||||
userManageService.getOne(new QueryWrapper<UserAccount>().eq(PermissionConstants.USER_NAME, username)).getRoles();
|
||||
return Result.success(tokenMap);
|
||||
}else{
|
||||
throw new AuthenticationException("密码错误");
|
||||
}
|
||||
}
|
||||
|
||||
private void saveAllUserInfoToRedis(UserAccount account) {
|
||||
stringRedisTemplate.opsForValue().set(PermissionConstants.USER_KEY+account.getId(),
|
||||
JSON.toJSONString(account),24,TimeUnit.HOURS);
|
||||
}
|
||||
|
||||
private void saveUserInfoToRedis(String username, UserAccount user) {
|
||||
stringRedisTemplate.opsForValue().set(PermissionConstants.USER_CACHE_KEY + username,
|
||||
JSON.toJSONString(user), 30 * 60, TimeUnit.MINUTES);
|
||||
}
|
||||
|
||||
private Result checkUser(String username, String password) {
|
||||
// 检查用户名和密码的合法性
|
||||
if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
|
||||
return new Result<>(400, "用户名或密码不能为空");
|
||||
}
|
||||
if (username.length() < 3 || username.length() > 20) {
|
||||
return new Result<>(400, "用户名长度必须在6-20个字符之间");
|
||||
}
|
||||
if (password.length() < 3 || password.length() > 20) {
|
||||
return new Result<>(400, "密码长度必须在6-20个字符之间");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -88,14 +152,17 @@ public class LoginControler {
|
|||
* 当认证服务返回给客户端的 JWT 也就是 access_token 过期后,客户端如果需要再次通过发送登录请求重新拿到 access_token会使得用户体验很不友好。
|
||||
* 而JWT 生成后是不能篡改里面的内容,即使是 JWT 的有效期也不行。所以延长 access_token 有效期的做法并不适合,而且如果长期保持一个 access_token 有效,
|
||||
* 也是不安全的。所以我们时常使用refresh token来进行token的刷新。
|
||||
*
|
||||
* <p>
|
||||
* 我们一般会把 refresh_token 设置的过期时间稍微长一点,比如两倍于 access_token,当 access_token 过期后,refresh_token 如果还没有过期,
|
||||
* 就可以利用两者的过期时间差进行重新生成令牌的操作,也就是刷新令牌,同时删除掉redis中缓存的旧令牌。
|
||||
*
|
||||
* @param token
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/token/refresh")
|
||||
public CommonResult<Object> refreshToken(@RequestHeader(value = "${auth.jwt.header}") String token){
|
||||
@RequestMapping(value = "/token/refresh",method = RequestMethod.GET)
|
||||
@ApiOperation(value = "刷新令牌")
|
||||
@ApiOperationSupport(author = "liz")
|
||||
public CommonResult<Object> refreshToken(@RequestHeader(value = "${auth.jwt.header}") String token) {
|
||||
token = com.auth.server.util.SecurityUtils.replaceTokenPrefix(token);
|
||||
|
||||
if (StringUtils.isEmpty(token)) {
|
||||
|
@ -105,7 +172,7 @@ public class LoginControler {
|
|||
|
||||
// 对Token解签名,并验证Token是否过期
|
||||
boolean isJwtNotValid = jwtTokenUtil.isTokenExpired(token);
|
||||
if(isJwtNotValid){
|
||||
if (isJwtNotValid) {
|
||||
return new CommonResult<>(ResponseCodeEnum.TOKEN_INVALID.getCode(),
|
||||
ResponseCodeEnum.TOKEN_INVALID.getMessage());
|
||||
}
|
||||
|
@ -122,7 +189,7 @@ public class LoginControler {
|
|||
// 如果用的不是 redis 中的 refreshToken 进行刷新令牌,则不能刷新。
|
||||
// 如果使用 redis 中已过期的 refreshToken 也不能刷新令牌。
|
||||
boolean isRefreshTokenNotExisted = jwtTokenUtil.isRefreshTokenNotExistCache(token);
|
||||
if(isRefreshTokenNotExisted){
|
||||
if (isRefreshTokenNotExisted) {
|
||||
return new CommonResult<>(ResponseCodeEnum.REFRESH_TOKEN_INVALID.getCode(),
|
||||
ResponseCodeEnum.REFRESH_TOKEN_INVALID.getMessage());
|
||||
}
|
||||
|
@ -130,6 +197,7 @@ public class LoginControler {
|
|||
//String us = jwtTokenUtil.getUserIdFromToken(token);
|
||||
Map<String, Object> tokenMap = jwtTokenUtil.refreshTokenAndGenerateToken(userId, username);
|
||||
|
||||
return new CommonResult<>(200, ResponseCodeEnum.SUCCESS.getMessage(),tokenMap);
|
||||
return new CommonResult<>(200, ResponseCodeEnum.SUCCESS.getMessage(), tokenMap);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 角色 controller层
|
||||
* 角色权限 controller层
|
||||
*/
|
||||
@RestController
|
||||
@Api(tags ="权限-API")
|
||||
|
|
|
@ -7,4 +7,5 @@ import com.baomidou.mybatisplus.extension.service.IService;
|
|||
public interface UserManageService extends IService<UserAccount> {
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.auth.server.service.impl;
|
||||
|
||||
import com.auth.common.entity.RolesPermission;
|
||||
import com.auth.common.enums.PermissionConstants;
|
||||
import com.auth.server.mapper.PermissionMapper;
|
||||
import com.auth.server.service.PermissionService;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
|
@ -18,29 +19,43 @@ import java.util.List;
|
|||
public class PermissionServiceImpl extends ServiceImpl<PermissionMapper, RolesPermission> implements PermissionService {
|
||||
@Autowired
|
||||
private PermissionMapper permissionMapper;
|
||||
|
||||
@Override
|
||||
public boolean permissionAdd(String roles, List<String> codeList) {
|
||||
RolesPermission rolesPermission = new RolesPermission();
|
||||
rolesPermission.setRole(roles);
|
||||
int result = 0;
|
||||
RolesPermission role = permissionMapper.selectOne(new QueryWrapper<RolesPermission>().eq("role",roles));
|
||||
RolesPermission role = getRoleByName(roles);
|
||||
|
||||
if(role!=null){
|
||||
//去掉头尾括号,并转为列表
|
||||
List<String> list = new java.util.ArrayList<>(Collections.singletonList(
|
||||
StringUtils.strip(role.getPermissionCode(), "[]")));
|
||||
//将新数据添加至列表
|
||||
list.addAll(codeList);
|
||||
|
||||
rolesPermission.setPermissionCode(list.toString());
|
||||
rolesPermission.setId(role.getId());
|
||||
result = permissionMapper.updateById(rolesPermission);
|
||||
}else {
|
||||
if (codeList!=null){
|
||||
rolesPermission.setPermissionCode(codeList.toString());
|
||||
}
|
||||
result = permissionMapper.insert(rolesPermission);
|
||||
if (role != null) {
|
||||
result = updateRolePermission(rolesPermission, role, codeList);
|
||||
} else {
|
||||
result = insertRolePermission(rolesPermission, codeList);
|
||||
}
|
||||
return result > 0;
|
||||
}
|
||||
|
||||
private RolesPermission getRoleByName(String roleName) {
|
||||
return permissionMapper.selectOne(new QueryWrapper<RolesPermission>().eq(PermissionConstants.ROLE, roleName));
|
||||
}
|
||||
|
||||
private int updateRolePermission(RolesPermission rolesPermission, RolesPermission role, List<String> codeList) {
|
||||
//去掉头尾括号,并转为列表
|
||||
List<String> list = new java.util.ArrayList<>(Collections.singletonList(
|
||||
StringUtils.strip(role.getPermissionCode(), "[]")));
|
||||
//将新数据添加至列表
|
||||
list.addAll(codeList);
|
||||
|
||||
rolesPermission.setPermissionCode(list.toString());
|
||||
rolesPermission.setId(role.getId());
|
||||
return permissionMapper.updateById(rolesPermission);
|
||||
}
|
||||
|
||||
private int insertRolePermission(RolesPermission rolesPermission, List<String> codeList) {
|
||||
if (codeList != null) {
|
||||
rolesPermission.setPermissionCode(codeList.toString());
|
||||
}
|
||||
return permissionMapper.insert(rolesPermission);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ server:
|
|||
port: 9092
|
||||
spring:
|
||||
application:
|
||||
name: engine-jwt-manage
|
||||
name: engine-auth
|
||||
redis:
|
||||
host: 115.159.33.152
|
||||
port: 6379
|
||||
|
|
|
@ -1,13 +1,31 @@
|
|||
package com.auth.server;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
|
||||
@SpringBootTest
|
||||
class EtlAuthServerApplicationTests {
|
||||
|
||||
@Autowired
|
||||
private BCryptPasswordEncoder bCryptPasswordEncoder;
|
||||
@Test
|
||||
void contextLoads() {
|
||||
public void enCoder() {
|
||||
String password="123";
|
||||
String encode = bCryptPasswordEncoder.encode(password);
|
||||
System.out.println("加密后的密码:"+encode);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void matchesPassword(){
|
||||
String encode="$2a$10$fEQQjl9rqSIWX/vHLy/LF.tovUIXInaR783YZXURMGMaUSIyefq4C";
|
||||
boolean matches = bCryptPasswordEncoder.matches("123", encode);
|
||||
if (matches){
|
||||
System.out.println("密码正确");
|
||||
}else {
|
||||
System.out.println("密码错误");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ server:
|
|||
port: 9092
|
||||
spring:
|
||||
application:
|
||||
name: engine-jwt-manage
|
||||
name: engine-auth
|
||||
redis:
|
||||
host: 115.159.33.152
|
||||
port: 6379
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -10,8 +10,7 @@
|
|||
{
|
||||
"name": "auth.jwt.enabled",
|
||||
"type": "java.lang.Boolean",
|
||||
"sourceType": "com.etl.jwt.config.AuthJwtProperties",
|
||||
"defaultValue": true
|
||||
"sourceType": "com.etl.jwt.config.AuthJwtProperties"
|
||||
},
|
||||
{
|
||||
"name": "auth.jwt.expiration",
|
||||
|
@ -27,8 +26,7 @@
|
|||
"name": "auth.jwt.pwd-param-name",
|
||||
"type": "java.lang.String",
|
||||
"description": "用户登录-密码参数名称",
|
||||
"sourceType": "com.etl.jwt.config.AuthJwtProperties",
|
||||
"defaultValue": "password"
|
||||
"sourceType": "com.etl.jwt.config.AuthJwtProperties"
|
||||
},
|
||||
{
|
||||
"name": "auth.jwt.secret",
|
||||
|
@ -43,15 +41,13 @@
|
|||
{
|
||||
"name": "auth.jwt.use-default-controller",
|
||||
"type": "java.lang.Boolean",
|
||||
"sourceType": "com.etl.jwt.config.AuthJwtProperties",
|
||||
"defaultValue": false
|
||||
"sourceType": "com.etl.jwt.config.AuthJwtProperties"
|
||||
},
|
||||
{
|
||||
"name": "auth.jwt.user-param-name",
|
||||
"type": "java.lang.String",
|
||||
"description": "用户登录-用户名参数名称",
|
||||
"sourceType": "com.etl.jwt.config.AuthJwtProperties",
|
||||
"defaultValue": "userId"
|
||||
"sourceType": "com.etl.jwt.config.AuthJwtProperties"
|
||||
}
|
||||
],
|
||||
"hints": []
|
||||
|
|
Loading…
Reference in New Issue