zoukankan      html  css  js  c++  java
  • 用户登录并返回token(springboot)

    何为token?【如果想直接看代码可以往下翻】

    使用基于 Token 的身份验证方法,在服务端不需要存储用户的登录记录。大概的流程是这样的:
    1. 客户端使用用户名跟密码请求登录
    2. 服务端收到请求,去验证用户名与密码
    3. 验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端
    4. 客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里
    5. 客户端每次向服务端请求资源的时候需要带着服务端签发的 Token
    6. 服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据

    token优点

    支持跨域访问: Cookie是不允许垮域访问的,这一点对Token机制是不存在的,前提是传输的用户认证信息通
    过HTTP头传输.
    无状态(也称:服务端可扩展行):Token机制在服务端不需要存储session信息,因为Token 自身包含了所有登
    录用户的信息,只需要在客户端的cookie或本地介质存储状态信息.
    更适用CDN: 可以通过内容分发网络请求你服务端的所有资料(如:javascript,HTML,图片等),而你的服
    务端只要提供API即可.
    去耦: 不需要绑定到一个特定的身份验证方案。Token可以在任何地方生成,只要在你的API被调用的时候,你
    可以进行Token生成调用即可.
    更适用于移动应用: 当你的客户端是一个原生平台(iOS, Android,Windows 8等)时,Cookie是不被支持的
    (你需要通过Cookie容器进行处理),这时采用Token认证机制就会简单得多。
    CSRF:因为不再依赖于Cookie,所以你就不需要考虑对CSRF(跨站请求伪造)的防范。
    性能: 一次网络往返时间(通过数据库查询session信息)总比做一次HMACSHA256计算 的Token验证和解析
    要费时得多.
    不需要为登录页面做特殊处理: 如果你使用Protractor 做功能测试的时候,不再需要为登录页面做特殊处理.
    基于标准化:你的API可以采用标准化的 JSON Web Token (JWT). 这个标准已经存在多个后端库(.NET, Ruby,
    Java,Python, PHP)和多家公司的支持(如:Firebase,Google, Microsoft)

    如何创建token【我这里用的是Jwt机制,有些公司用的是自己的生成方法哈】

    (1)创建maven工程,引入依赖

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

    (2)使用工具类JwtUtils

     1 /**
     2  * @author: Mr.Yang
     3  * @create: 2020-02-13 21:19
     4  **/
     5 @Getter
     6 @Setter
     7 @ConfigurationProperties("jwt.config")
     8 public class JwtUtils {
     9     //签名私钥
    10     private String key;
    11     //签名失效时间
    12     private Long failureTime;
    13 
    14     /**
    15      * 设置认证token
    16      *
    17      * @param id      用户登录ID
    18      * @param subject 用户登录名
    19      * @param map     其他私有数据
    20      * @return
    21      */
    22     public String createJwt(String id, String subject, Map<String, Object> map) {
    23 
    24         //1、设置失效时间啊
    25         long now = System.currentTimeMillis();  //毫秒
    26         long exp = now + failureTime;
    27 
    28         //2、创建JwtBuilder
    29         JwtBuilder jwtBuilder = Jwts.builder().setId(id).setSubject(subject)
    30                 .setIssuedAt(new Date())
    31                 //设置签名防止篡改
    32                 .signWith(SignatureAlgorithm.HS256, key);
    33 
    34         //3、根据map设置claims
    35         for (Map.Entry<String, Object> entry : map.entrySet()) {
    36             jwtBuilder.claim(entry.getKey(), entry.getValue());
    37         }
    38         jwtBuilder.setExpiration(new Date(exp));
    39 
    40         //4、创建token
    41         String token = jwtBuilder.compact();
    42         return token;
    43     }
    44 
    45     /**
    46      * 解析token
    47      *
    48      * @param token
    49      * @return
    50      */
    51     public Claims parseJwt(String token) {
    52         Claims claims = Jwts.parser().setSigningKey(key).parseClaimsJws(token).getBody();
    53         return claims;
    54     }
    55 
    56 }
    View Code

    注意:

    @ConfigurationProperties("jwt.config")需要在配置文件中配置

    (3)配置JwtUtils类
    1     /**
    2      * 配置jwt
    3      *
    4      * @return
    5      */
    6     @Bean
    7     public JwtUtils jwtUtils() {
    8         return new JwtUtils();
    9     }

    (4)编写登录方法

      1、编写DAO层

     1 /**
     2  * @author: Mr.Yang
     3  * @create: 2020-02-13 21:55
     4  **/
     5 @Repository
     6 public interface UserDAO {
     7 
     8     public User selectByMobileUser(String mobile);
     9 
    10     public User selectByIdUser(String id);
    11 }
    View Code

      2、编写xml写Sql

     <select id="selectByMobileUser" parameterType="string" resultMap="userMap">
            select *
            from bs_user
            where mobile = #{mobile}
        </select>
    View Code

      3、编写service层

     /**
         * 根据mobile查询用户
         *
         * @param mobile
         * @return
         */
        public User selectByMobile(String mobile) {
            return userDAO.selectByMobileUser(mobile);
        }
    View Code

      4、编写controller层

     1  /**
     2      * 用户登录
     3      * 1.通过service根据mobile查询用户
     4      * 2.比较password
     5      * 3.生成jwt信息
     6      *
     7      * @param loginMap
     8      * @return
     9      * @requestBody把请求数据封装(前端以json方式传)
    10      */
    11     @RequestMapping(value = "/login", method = RequestMethod.POST)
    12     public Result login(@RequestBody Map<String, String> loginMap) {
    13         String mobile = loginMap.get("mobile");
    14         String password = loginMap.get("password");
    15         User user = userService.selectByMobile(mobile);
    16         //登录失败
    17         if (user == null || !user.getPassword().equals(password)) {
    18             //既可以使用抛异常,也可使用直接返回错误码(推荐)
    19             return new Result(ResultCode.MOBILEORPASSWORDERROR);
    20         } else {
    21             //其他数据以map集合存放在token中
    22             Map<String, Object> dataMap = new HashMap<>();
    23             dataMap.put("companyId", user.getCompanyId());
    24             dataMap.put("companyName", user.getCompanyName());
    25             //生成token并存入数据返回
    26             String token = jwtUtils.createJwt(user.getId(), user.getUsername(), dataMap);
    27             return new Result(Result.SUCCESS(), token);
    28         }
    29     }
    View Code

      5、测试

    data就是返回的token,里面存有用户ID,用户姓名及以map形式存入的数据(这里主要看前端需要什么就存什么)


    (6)用户登录成功之后,获取用户信息

     1  /**
     2      * 用户登录成功之后,获取用户信息
     3      * 1.获取用户id
     4      * 2.根据用户id查询用户
     5      * 3.构建返回值对象
     6      * 4.响应
     7      *
     8      * @param request
     9      * @return
    10      * @throws Exception
    11      */
    12     @RequestMapping(value = "/profile", method = RequestMethod.POST)
    13     public Result profile(HttpServletRequest request) throws PendingException, Exception {
    14 
    15         /**
    16          * 从请求头信息中获取token数据
    17          *   1.获取请求头信息:名称=Authorization(前后端约定)
    18          *   2.替换Bearer+空格
    19          *   3.解析token
    20          *   4.获取clamis
    21          */
    22 
    23 
    24         //1.获取请求头信息:名称=Authorization(前后端约定)
    25         String authorization = request.getHeader("Authorization");
    26         if (StringUtils.isEmpty(authorization)) {
    27 //            throw new PendingException(ResCode.UNAUTHENTICATED);
    28             //系统未捕捉到请求头信息
    29             throw new CommonException(ResultCode.UNAUTHENTICATED);
    30         }
    31         //2.替换Bearer+空格
    32         String token = authorization.replace("Bearer ", "");
    33 
    34         //3.解析token
    35         Claims claims = jwtUtils.parseJwt(token);
    36         //4.获取clamis
    37         String userId = claims.getId();
    38 
    39         //  String userId = "U01";
    40         User user = userService.selectByIdUser(userId);
    41 
    42         /**此处只是为了获取token中的用户数据,所有只简单返回用户对象,
    43          * 工作则按实际要求多表查询需要数据(根据用户ID查询权限)
    44          */
    45 
    46         return new Result(ResultCode.SUCCESS, user);
    47     }
    View Code

    (7)测试

  • 相关阅读:
    Wannafly挑战赛14 F.细胞
    D 勤奋的杨老师(二)(最小割)
    三分算法求最值
    初识最大流
    初识数据结构
    决策型DP
    哈希表
    【BZOJ】1878: [SDOI2009]HH的项链 (主席树)
    【HDU】1520 Anniversary party(树形dp)
    【UVa】1606 Amphiphilic Carbon Molecules(计算几何)
  • 原文地址:https://www.cnblogs.com/exce-ben/p/12310448.html
Copyright © 2011-2022 走看看