首页 > 其他分享 >SpringCloud游戏平台改造-Day2

SpringCloud游戏平台改造-Day2

时间:2022-12-03 17:11:24浏览次数:55  
标签:Map return 游戏 SpringCloud Day2 resultMap token public String

Day2

今天主要目的是接入SpringSecurity和JWT,不多说开干!

Day1

Day2

接入SpringSecurity

Step1

实现来自SpringSecurity的UserDetailService接口,实现它的loaduserByUserName, 实现与数据库中数据的绑定,后续也是通过这个进行验证

Step2

实现ScurityConfig类,配置密码的加密解密,公开链接/拦截链接的配置。以及一些Filter的加载

    /**
     * 密码加密
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                // 下面的链接是公开的
                .antMatchers("/user/account/token/", "/user/account/register/", "/websocket/**", "/test").permitAll()
                .antMatchers("/pk/start/game/").hasIpAddress("127.0.0.1")
                .antMatchers("/pk/receive/bot/move/").hasIpAddress("127.0.0.1")
                .antMatchers(HttpMethod.OPTIONS).permitAll()
                .anyRequest().authenticated();
        http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
    }

Step3

实现JwtUtil,解析和生成JwtToken

    public static String getUUID() {
        return UUID.randomUUID().toString().replaceAll("-", "");
    }

    /**
     * 生成JWT-token
     * @param subject
     * @return
     */
    public static String createJWT(String subject) {
        JwtBuilder builder = getJwtBuilder(subject, null, getUUID());
        return builder.compact();
    }

    /**
     * 获取JWT builder
     * @param subject
     * @param ttlMills
     * @param uuid
     * @return
     */
    private static JwtBuilder getJwtBuilder(String subject, Long ttlMills, String uuid) {
        // 1. 指定签名算法
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        // 2. 生成秘钥
        SecretKey secretKey = generalKey();
        long nowMills = System.currentTimeMillis();
        Date now = new Date(nowMills);
        if (ttlMills == null) {
            ttlMills = Constants.JwtConstants.JWT_TTL;
        }
        long expMills = ttlMills + nowMills;
        Date expDate = new Date(expMills);
        return Jwts.builder().setId(uuid).setSubject(subject)
                .setIssuer("chin").setIssuedAt(now).signWith(signatureAlgorithm, secretKey)
                .setExpiration(expDate);
    }

    /**
     * 生成秘钥
     * @return
     */
    public static SecretKey generalKey() {
        byte[] encodeKey = Base64.getDecoder().decode(Constants.JwtConstants.JWT_KEY);
        return new SecretKeySpec(encodeKey, 0, encodeKey.length, "HmacSHA256");
    }

    public static Claims parseJWT(String jwt) throws Exception {
        SecretKey secretKey = generalKey();
        return Jwts.parser()
                .setSigningKey(secretKey)
                .parseClaimsJws(jwt)
                .getBody();
    }

Step4

在网关处实现Filter,去拦截header处的JwtToken, 拦截出来的JWTToken将他进行解析,绑定在我们的SecurityContextHolder里面,在之后的getInfo的时候可以将他取出。

Step5

其余配置,如跨域配置

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        HttpServletRequest request = (HttpServletRequest) req;

        String origin = request.getHeader("Origin");
        if(origin!=null) {
            response.setHeader("Access-Control-Allow-Origin", origin);
        }

        String headers = request.getHeader("Access-Control-Request-Headers");
        if(headers!=null) {
            response.setHeader("Access-Control-Allow-Headers", headers);
            response.setHeader("Access-Control-Expose-Headers", headers);
        }

        response.setHeader("Access-Control-Allow-Methods", "*");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Credentials", "true");

        chain.doFilter(request, response);
    }

实现接口和方法

领域层

领域层我目前的设计是,分为了安全配置领域和用户领域两个部分。

  • 安全配置领域就是完成SpringSecurity相关的一系列配置
  • 用户领域就是完成获取jwt-token、用户登录注册等增删改查的操作

贴出主要代码:

/**
 * @author qi
 */
@Service
public class UserService implements IUserService {

    private Logger logger = LoggerFactory.getLogger(UserService.class);

    @Resource
    private IUserRepository userRepository;

    @Resource
    private AuthenticationManager authenticationManager;

    @Override
    public Map<String, String> token(String username, String password) {
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
        // 1. 让Security去完成登录
        Authentication authenticate = authenticationManager.authenticate(authenticationToken);
        UserDetailsImpl user = (UserDetailsImpl) authenticate.getPrincipal();
        UserDetail userDetail = user.getUserDetail();

        // 2. 生成jwt-token
        String jwt = JwtUtil.createJWT(userDetail.getId().toString());
        logger.info("user: {} , token: {}", userDetail, jwt);
        Map<String, String> resultMap = new HashMap<>();
        resultMap.put("error_message", "success");
        resultMap.put("token", jwt);
        return resultMap;
    }

    @Override
    public Map<String, String> userInfo() {
        UsernamePasswordAuthenticationToken authentication = (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
        UserDetailsImpl user = (UserDetailsImpl) authentication.getPrincipal();
        UserDetail userDetail = user.getUserDetail();

        Map<String, String> resultMap = new HashMap<>();
        resultMap.put("error_message", "success");
        resultMap.put("id", userDetail.getId().toString());
        resultMap.put("username", userDetail.getUsername());
        resultMap.put("photo", userDetail.getPhoto());
        resultMap.put("rating", userDetail.getRating().toString());
        return resultMap;
    }

    @Override
    public Map<String, String> insertUser(String username, String password, String photo, Integer rating) {
        userRepository.insertUser(username,
                password,
                photo,
                rating);
        Map<String, String> resultMap = new HashMap<>();
        resultMap.put("error_message", "success");
        return resultMap;
    }

    @Override
    public Map<String, String> updateUser(String username, String photo, Integer rating) {
        boolean success = userRepository.updateUser(username, photo, rating);
        Map<String, String> resultMap = new HashMap<>();
        if (success) {
            resultMap.put("error_message", "success");
        } else {
            resultMap.put("error_message", "delete failed");
        }
        return resultMap;
    }

    @Override
    public Map<String, String> checkUserToken(String token) {
        return null;
    }

    @Override
    public Map<String, String> deleteUser(Integer uId) {
        boolean success = userRepository.deleteUser(uId);
        Map<String, String> resultMap = new HashMap<>();
        if (success) {
            resultMap.put("error_message", "success");
        } else {
            resultMap.put("error_message", "delete failed");
        }
        return resultMap;
    }


}

仓储层

仓储层目前设计还是比较简单,就是基于User这个表的pojo,dao以及实现了领域层的接口,并设计了一些常量。

接口层

接口层就是实现了提供的两个接口,具体如下:

    @PostMapping("/user/account/token/")
    public Map<String, String> getToken(@RequestParam Map<String, String> map) {
        logger.info("username: {}", map.get("username"));
        return userService.token(map.get("username"), map.get("password"));
    }

    @GetMapping("/user/account/info/")
    public Map<String, String> getInfo() {
        return userService.userInfo();
    }

应用程序层

这里由于逻辑都是较为简单,所以就是规范了一下接口层所要用到的结果输入输出。

/**
 * @author qi
 */
public interface IUserService {

    /**
     * 登录并分发JWT-token
     * @return
     */
    Map<String, String> token(String username, String password);

    /**
     * 获取用户信息
     * @return
     */
    Map<String, String> userInfo();

    /**
     * 注册用户
     * @param username
     * @param password
     * @param photo
     * @param rating
     * @return
     */
    Map<String, String> insertUser(String username, String password, String photo, Integer rating);

    /**
     * 更新用户
     * @param username
     * @param photo
     * @param rating
     * @return
     */
    Map<String, String> updateUser(String username, String photo, Integer rating);

    /**
     * 检查用户的JWT=token是否合法
     * @param token
     * @return
     */
    Map<String, String> checkUserToken(String token);

    /**
     * 删除用户
     * @param uId
     * @return
     */
    Map<String, String> deleteUser(Integer uId);
}

总结

今天是为了实现登录的内容,后续增删改查的部分还需要补充一下,不过就是按部就班填一填罢了。

下一步的设计思路,把注册中心、网关、OSS存储系统的服务给拉起来。

标签:Map,return,游戏,SpringCloud,Day2,resultMap,token,public,String
From: https://www.cnblogs.com/azxx/p/16948355.html

相关文章

  • SpringCloud Alibaba(七) - JWT(JSON Web Token)
    原文链接:JWT详解:https://blog.csdn.net/weixin_45070175/article/details/1185592721、什么是JWT通俗地说,JWT的本质就是一个字符串,它是将用户信息保存到一个Json字符串......
  • js-day05-猜数字游戏和随机点名升华
     猜数字游戏<script>    //随机数    functiongetRandom(min,max){      returnMath.floor(Math.random()*(max-min+1))+min......
  • 猜数字游戏
    前言:在介绍猜数字游戏时,上一篇博客忘记写了,我们先来了解一下goto语句1.goto语句忠告:慎用goto语句C语言中提供了可以随意滥用的goto语句和标记跳转的标号。从理论上goto语......
  • 制作一个跳跃的小球游戏
    #-*-coding:utf-8-*-importsys#导入sys模块importpygame#导入pygame模块pygame.init()#初始化pygamesize=width,height=640,480#设置窗口s......
  • python游戏编程
     一,实验目的Pygame是跨平台Python模块,专为电子游戏设计(包含图像、声音),创建在SDL基础上,允许实时电子游戏研发而不被低级语言舒服。基于这一设想,所有需要的游戏功能和理......
  • 第13章 pygame游戏编程
    一、实验目的和要求学会Pygame的基本应用二、实验环境软件版本:Python3.1064_bit三、实验过程1、实例1:制作一个跳跃的小游戏(1)代码如下:#-*-coding:utf-8-*-im......
  • Pygame小球游戏
    importsysimportpygamepygame.init()size=width,height=1000,800screen=pygame.display.set_mode(size)color=(0,0,0)ball=pygame.image.load("ball.......
  • 第十三章 Pygame游戏编程
     实例01:制作一个跳跃的小球小游戏 创建一个游戏窗口,然后在窗口内创建一个小球,以一定的速度移动小球,当小球碰到游戏窗口的边缘时,小球弹回,继续移动。  代码如下......
  • SpringCloud Alibaba(六) - Seata 分布式事务锁
    1、Seata简介1.1Seata是什么Seata是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata将为用户提供了AT、TCC、SAGA和XA事务模式......
  • Python实验报告——第13章 Pygame游戏编程
    实验报告实例01:制作一个跳跃的小球游戏代码如下:importsysimportpygamepygame.init()size=width,height=640,480screem=pygame.display.set_mode(size)c......