对用户的密码进行加密以及只允许有权限的管理员进行删除用户

1. 用户密码加密

使用 springsecurity 中的 BCryptPasswordEncoder 方法对密码进行加密 (encode) 与密码匹配 (matches).

方法采用 SHA-256 + 随机盐 + 密钥 对密码进行加密.

SHA 系列是 Hash 算法, 不是加密算法. (加密算法意味着可以解密, 采用 Hash 意味着其过程不可逆)

1. bCryptPasswordEncoder.encode() 对密码加密
2. bCryptPasswordEncoder.matches() 密码进行匹配

1.1 导包

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-security</artifactId>
</dependency>

1.2 设置配置文件 SecurityConfig

加密过程所有路径都可以通过

package com.springCloud.user.config.security;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

/**
 * EnableWebSecurity: Introducing Security Configuration Permissions.
 */
@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     * Define authorization rules.
     *
     * @param http http
     * @throws Exception Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //super.configure(http);
        /* Setting Path Access Permissions. */
        /*
         * authorizeRequests: 全注解配置实现的开端, 表示开始需要权限.
         * 需要的权限分为两部分: 第一部分是拦截的路径, 第二部分该路径需要的访问权限.
         * mvcMatchers: 表示拦截什么路径.
         * permitAll: 任何权限都可以访问.
         * anyRequest: 任何请求.
         * authenticated: 认证后才可以访问.
         * .and().csrf().disable(); 固定写法, 使 csrf 拦截失败.
         * */
        http.authorizeRequests()
                .mvcMatchers("/**")
                .permitAll()
                .anyRequest()
                .authenticated()
                .and().csrf().disable();
    }

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

}


1.3 对 user 进行加密


    private IdWorker idWorker;
    private BCryptPasswordEncoder bCryptPasswordEncoder;
    
    
    /**
     * 获取容器对象
     */
    @Autowired
    private UserServiceImpl(IdWorker idWorker,
                            BCryptPasswordEncoder bCryptPasswordEncoder) {
        this.idWorker = idWorker;
        this.bCryptPasswordEncoder = bCryptPasswordEncoder;
    }


    /**
     * 添加用户并保存
     *
     * @param user 用户
     */
    @Override
    public void save(User user) {
        // 随机生成 id 号 (雪花算法)
        user.setId(String.valueOf(idWorker.nextId()));
        user.setLoginPassword(bCryptPasswordEncoder.encode(user.getLoginPassword()));
        user.setPayPassword(bCryptPasswordEncoder.encode(user.getPayPassword()));
        userDao.save(user);
    }

    

在这里插入图片描述

1.4 对登录匹配密码


    /**
     * 手机号登录
     *
     * @param user 用户
     * @return User
     */
    @Override
    public User login_phone(User user) {
        User byPhone = userDao.findByPhone(user.getPhone());
        if (byPhone != null && bCryptPasswordEncoder.matches(user.getLoginPassword(), byPhone.getLoginPassword())) {
            return byPhone;
        }
        return null;
    }

2. 有权限的管理员可以删除用户

JSON Web Token (JWT) 是目前最流行的跨域身份验证解决方案.

  1. JWT 跨域身份验证.
  2. Token 的方式做登录身份校验去取 Redis 中的缓存的用户信息.
  3. 服务器不保存任何会话数据, 使服务器处于无状态.
  4. 使用 Base64 URL 算法将所设 JSON 对象转换为字符串保存.
  5. JWT 不仅可用于认证, 还可用于信息交换.
  6. JWT 的三个部分: JWT头, 有效载荷, 签名.
    在这里插入图片描述

2.1 导包

<dependency>
	<groupId>io.jsonwebtoken</groupId>
	<artifactId>jjwt</artifactId>
	<version>0.9.1</version>
</dependency>

2.2 common 模块中创建 util 类 JWT

package com.springCloud.common.util;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.util.Date;

@ConfigurationProperties(prefix = "jwt.config")
@Component
@Data
public class JWT {

    private String key;

    private long expiration;

    /**
     * 创建 JWT
     * @param id 用户的 id 号
     * @param subject 用户名
     * @param role 用户的角色
     * @return JWT 编码.
     */
    public String createJWT(String id, String subject, String role) {
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        JwtBuilder jwtBuilder = Jwts.builder()
                .setId(id)
                .setSubject(subject)
                .setIssuedAt(now)
                .signWith(SignatureAlgorithm.HS256, key)
                .claim("role", role);
        if (expiration > 0) {
            jwtBuilder.setExpiration(new Date(nowMillis + expiration));
        }
        return jwtBuilder.compact();
    }

    /**
     * 解析 JWT
     * @param jwtString JWT 编码字符串
     * @return String
     */
    public Claims parseJWT(String jwtString) {
        return Jwts.parser()
                .setSigningKey(key)
                .parseClaimsJws(jwtString)
                .getBody();
    }

}

2.3 user 模块中创建 JWT 的配置类

package com.springCloud.user.config.jwt;

import com.springCloud.common.util.JWT;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class JwtConfig {

    @Bean
    public JWT jwt() {
        return new JWT();
    }

}

2.4 user 模块中创建拦截器

将拦截器放在配置中

package com.springCloud.user.config.interceptor;

import com.springCloud.user.interceptor.JwtInterceptor;
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 InterceptorConfig implements WebMvcConfigurer {

    private JwtInterceptor jwtInterceptor;

    @Autowired
    public InterceptorConfig(JwtInterceptor jwtInterceptor) {
        this.jwtInterceptor = jwtInterceptor;
    }

    /**
     * Registered Interceptor
     *
     * @param registry registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 注册拦截器要声明拦截器对象和拦截器请求.
        registry.addInterceptor(jwtInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns("/**/login**/**");
    }

}

拦截器

package com.springCloud.user.interceptor;

import com.springCloud.common.util.JWT;
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class JwtInterceptor implements HandlerInterceptor {

    private JWT jwt;

    @Autowired
    private JwtInterceptor(JWT jwt) {
        this.jwt = jwt;
    }


    /**
     * 如论如何都需要放行, 而拦截需要在操作中去判断.
     * login 中 拦截器只需要将请求头中包括 token 的令牌进行解析.
     *
     * @param request  请求
     * @param response 响应
     * @param handler  处理
     * @return boolean
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // 得到请求头中的 Authorization.
        String header = request.getHeader("Authorization");
        // 判断是否进行拦截
        if (header != null && !"".equals(header) && header.startsWith("Bearer ")) {
            // 得到 token
            String token = header.substring(7);
            // 进行对 token 解析.
            try {
                Claims claims = jwt.parseJWT(token);
                // 得到登录的角色
                String role = (String) claims.get("role");
                if ("admin".equals(role)) {
                    request.setAttribute("token_admin", token);
                }
                if ("user".equals(role)) {
                    request.setAttribute("token_user", token);
                }
            } catch (Exception e) {
                throw new RuntimeException("令牌不正确");
            }

        }
        return true;
    }

}

2.5 user 模块中的 controller


    private UserService userService;
    private RedisTemplate<String, String> redisTemplate;
    private HttpServletRequest request;
    private JWT jwt;

    /**
     * 获取容器对象
     *
     * @param userService 识别 userService 容器对象
     */
    @Autowired
    private UserController(UserService userService,
                           RedisTemplate<String, String> redisTemplate,
                           HttpServletRequest request,
                           JWT jwt) {
        this.userService = userService;
        this.redisTemplate = redisTemplate;
        this.request = request;
        this.jwt = jwt;
    }

    /**
     * 登录用户时需要前后端通话的操作 JWT
     * @param user 用户
     * @return Result
     */
    private Result login_jwt(User user) {
        String token = this.jwt.createJWT(user.getId(), user.getName(), "user");
        Map<String, Object> map = new HashMap<>();
        map.put("role", "user");
        map.put("token", token);
        return new Result(StatusCode.OK, true, "用户登录成功", map);
    }

    /**
     * 用户名登录
     *
     * @param user 用户
     * @return Result
     */
    @PostMapping("/login_name")
    public Result login_name(@RequestBody User user) {
        User login = userService.login_name(user);
        if (login == null) {
            return new Result(StatusCode.LOGIN_ERROR, false, "用户登录失败");
        }
        // 登录成功了, 需要进行前后端通话的操作. JWT
        return login_jwt(user);
    }

    /**
     * 手机号登录
     *
     * @param user 用户
     * @return Result
     */
    @PostMapping("/login_phone")
    public Result login_phone(@RequestBody User user) {
        User login = userService.login_phone(user);
        if (login == null) {
            return new Result(StatusCode.LOGIN_ERROR, false, "用户登录失败");
        }
        // 登录成功了, 需要进行前后端通话的操作. JWT
        return login_jwt(user);
    }

同理: admin 也一样的.

猜你喜欢

转载自blog.csdn.net/YKenan/article/details/105955189