微服务 管理员登录功能实现案例

目录

一、添加登录返回数据结构类

二、添加登录的控制器

三、添加登录实现的服务

四、远程调用Feign的类

五、Mapper实现

六、测试访问


一、添加登录返回数据结构类

package com.dragonwu.model;

import com.dragonwu.domain.SysMenu;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.security.core.authority.SimpleGrantedAuthority;

import java.util.List;

/**
 * 登录成功的结果
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(value = "登录的结果")
public class LoginResult {
    /**
     * 登录成功的token,来自我们的authorization-server 里面的
     */
    @ApiModelProperty(value = "登录成功的token,来自我们的authorization-server 里面的")
    private String token ;

    /**
     * 该用户的菜单数据
     */
    @ApiModelProperty(value = "该用户的菜单数据")
    private List<SysMenu> menus ;

    /**
     * 该用户的权限数据
     */
    @ApiModelProperty(value = "该用户的权限数据")
    private List<SimpleGrantedAuthority> authorities ;
}

二、添加登录的控制器

package com.dragonwu.controller;

import com.dragonwu.model.LoginResult;
import com.dragonwu.service.SysLoginService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * 登录的控制器
 */
@RestController
@Api(tags = "登录的控制器")
public class SysLoginController {

    @Autowired
    private SysLoginService loginService;

    @PostMapping("/login")
    @ApiOperation(value = "后台管理人员登录")
    @ApiImplicitParams(
            {
                    @ApiImplicitParam(name = "username", value = "用户名称"),
                    @ApiImplicitParam(name = "password", value = "用户的密码"),
            }
    )
    public LoginResult login(
            @RequestParam(required = true) String username, // 用户名称
            @RequestParam(required = true) String password  // 用户的密码
    ) {
        return loginService.login(username, password);
    }

}

三、添加登录实现的服务

登录服务

package com.dragonwu.service;

import com.dragonwu.model.LoginResult;

/**
 * 登录的接口
 */
public interface SysLoginService {

    /**
     * 登录的实现
     * @param username
     *  用户名
     * @param password
     *
     * 用户的密码
     * @return
     * 登录的结果
     */
    LoginResult login(String username ,String password) ;
}

实现类

package com.dragonwu.service.impl;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.enums.ApiErrorCode;
import com.baomidou.mybatisplus.extension.exceptions.ApiException;
import com.dragonwu.domain.SysMenu;
import com.dragonwu.feign.JwtToken;
import com.dragonwu.feign.OAuth2FeignClient;
import com.dragonwu.model.LoginResult;
import com.dragonwu.service.SysLoginService;
import com.dragonwu.service.SysMenuService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.jwt.Jwt;
import org.springframework.security.jwt.JwtHelper;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@Slf4j
public class SysLoginServiceImpl implements SysLoginService {

    @Autowired
    private OAuth2FeignClient oAuth2FeignClient;

    @Autowired
    private SysMenuService sysMenuService ;

    @Value("${basic.token:Basic Y29pbi1hcGk6Y29pbi1zZWNyZXQ=}")
    private String basicToken ;

    @Autowired
    private StringRedisTemplate redisTemplate ;
    /**
     * 登录的实现
     *
     * @param username 用户名
     * @param password 用户的密码
     * @return 登录的结果
     */
    @Override
    public LoginResult login(String username, String password) {
        log.info("用户{}开始登录", username);
        // 1 获取token 需要远程调用authorization-server 该服务
        ResponseEntity<JwtToken> tokenResponseEntity = oAuth2FeignClient.getToken("password", username, password, "admin_type", basicToken);
        if(tokenResponseEntity.getStatusCode()!= HttpStatus.OK){
            throw new ApiException(ApiErrorCode.FAILED) ;
        }
        JwtToken jwtToken = tokenResponseEntity.getBody();
        log.info("远程调用授权服务器成功,获取的token为{}", JSON.toJSONString(jwtToken,true));
        String token = jwtToken.getAccessToken() ;

        // 2 查询我们的菜单数据
        Jwt jwt = JwtHelper.decode(token);
        String jwtJsonStr = jwt.getClaims();
        JSONObject jwtJson = JSON.parseObject(jwtJsonStr);
        Long userId = Long.valueOf(jwtJson.getString("user_name")) ;
        List<SysMenu> menus = sysMenuService.getMenusByUserId(userId);

        // 3 权限数据怎么查询 -- 不需要查询的,因为我们的jwt 里面已经包含了
        JSONArray authoritiesJsonArray = jwtJson.getJSONArray("authorities");
        List<SimpleGrantedAuthority> authorities = authoritiesJsonArray.stream() // 组装我们的权限数据
                                                        .map(authorityJson->new SimpleGrantedAuthority(authorityJson.toString()))
                                                        .collect(Collectors.toList());
        // 1 将该token 存储在redis 里面,配置我们的网关做jwt验证的操作
        redisTemplate.opsForValue().set(token,"", jwtToken.getExpiresIn() ,TimeUnit.SECONDS);
        //2 我们返回给前端的Token 数据,少一个bearer:
        return new LoginResult(jwtToken.getTokenType()+" "+token, menus, authorities);
    }
}

系统菜单服务

package com.dragonwu.service;

import com.dragonwu.domain.SysMenu;
import com.baomidou.mybatisplus.extension.service.IService;

import java.util.List;

 
public interface SysMenuService extends IService<SysMenu>{
        /**
         * 通过用户的id 查询用户的菜单数据
         * @param userId
         * @return
         */

        List<SysMenu> getMenusByUserId(Long userId);

}

实现类

package com.bjsxt.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dragonwu.domain.SysMenu;
import com.dragonwu.mapper.SysMenuMapper;
import com.dragonwu.service.SysMenuService;
import com.dragonwu.service.SysRoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements SysMenuService{

    @Autowired
    private SysRoleService sysRoleService ;

    @Autowired
    private SysMenuMapper sysMenuMapper ;

    /**
     * 通过用户的id 查询用户的菜单数据
     *
     * @param userId
     * @return
     */
    @Override
    public List<SysMenu> getMenusByUserId(Long userId) {
        // 1 如果该用户是超级管理员->>拥有所有的菜单
        if(sysRoleService.isSuperAdmin(userId)){
            return list() ; // 查询所有
        }
        // 2 如果该用户不是超级管理员->>查询角色->查询菜单
        return sysMenuMapper.selectMenusByUserId(userId);
    }

}

角色管理服务

package com.dragonwu.service;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.dragonwu.domain.SysRole;
import com.baomidou.mybatisplus.extension.service.IService;

public interface SysRoleService extends IService<SysRole>{


    /**
     * 判断一个用户是否为超级的管理员
     * @param userId
     * @return
     */
    boolean isSuperAdmin(Long userId);

    /**
     * 使用角色的名称模糊分页角色查询
     * @param page
     * 分页数据
     * @param name
     *  角色的名称
     * @return
     */
    Page<SysRole> findByPage(Page<SysRole> page, String name);

}

实现类

package com.dragonwu.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dragonwu.domain.SysRole;
//import com.dragonwu.mapper.SysPrivilegeMapper;
import com.dragonwu.mapper.SysRoleMapper;
import com.dragonwu.service.SysRoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

//import java.io.Serializable;

@Service
public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> implements SysRoleService {

    @Autowired
    private SysRoleMapper sysRoleMapper;

//    @Autowired
//    private SysPrivilegeMapper sysPrivilegeMapper ;
//
//
//    /**
//     * 根据 ID 查询
//     *
//     * @param id 主键ID
//     */
//    @Override
//    public SysRole getById(Serializable id) {
//        SysRole sysRole = super.getById(id);
//        sysRole.setPrivileges(sysPrivilegeMapper.selectByRoleId(sysRole.getId()));
//        return sysRole;
//    }

    /**
     * 判断一个用户是否为超级的管理员
     *
     * @param userId
     * @return
     */
    @Override
    public boolean isSuperAdmin(Long userId) {
        // 当用户的角色code 为:ROLE_ADMIN 时,该用户为超级的管理员
        // 用户的id->用户的角色->该角色的Code是否为ROLE_ADMIN
        String roleCode = sysRoleMapper.getUserRoleCode(userId);
        if (!StringUtils.isEmpty(roleCode) && roleCode.equals("ROLE_ADMIN")) {
            return true;
        }
        return false;
    }

    /**
     * 使用角色的名称模糊分页角色查询
     *
     * @param page 分页数据
     * @param name 角色的名称
     * @return
     */
    @Override
    public Page<SysRole> findByPage(Page<SysRole> page, String name) {
        return page(page, new LambdaQueryWrapper<SysRole>().like(
                !StringUtils.isEmpty(name),
                SysRole::getName,
                name
        ));
    }
}

四、远程调用Feign的类

package com.dragonwu.feign;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestParam;

@FeignClient(value = "authorization-server")
public interface OAuth2FeignClient {

    @PostMapping("/oauth/token")
    ResponseEntity<JwtToken> getToken(
            @RequestParam("grant_type") String grantType , // 授权类型
            @RequestParam("username") String username , // 用户名
            @RequestParam("password") String  password , // 用户的密码
            @RequestParam("login_type")  String loginType,  // 登录的类型
            @RequestHeader("Authorization") String basicToken // Basic Y29pbi1hcGk6Y29pbi1zZWNyZXQ= 由第三方客户端信息加密出现的值
    ) ;
}
package com.dragonwu.feign;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;

@Data
public class JwtToken {
    /**
     * access_token
     */
    @JsonProperty("access_token")
    private String accessToken;

    /**
     * token类型
     */
    @JsonProperty("token_type")
    private String tokenType;

    /**
     * refresh_token
     */
    @JsonProperty("refresh_token")
    private String refreshToken;

    /**
     * 过期时间
     */
    @JsonProperty("expires_in")
    private Long expiresIn;


    /**
     * token的范围
     */
    private String scope;

    /**
     * 颁发的凭证
     */
    private String jti;
}

启动类开发Feign调用

@EnableFeignClients

五、Mapper实现

package com.dragonwu.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.dragonwu.domain.SysMenu;

import java.util.List;

public interface SysMenuMapper extends BaseMapper<SysMenu> {

    /**
     * 通过用户的id 查询用户的菜单数据
     * @param userId
     * @return
     */
    List<SysMenu> selectMenusByUserId(Long userId);

    /**
     * 使用角色的Id 查询所有菜单列表
     * @param roleId
     * @return
     */
    List<SysMenu> selectMenusByRoleId(Long roleId);
}

SysMenuMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.dragonwu.mapper.SysMenuMapper">
  <resultMap id="BaseResultMap" type="com.dragonwu.domain.SysMenu">
    <!--@mbg.generated-->
    <!--@Table sys_menu-->
    <id column="id" jdbcType="BIGINT" property="id" />
    <result column="parent_id" jdbcType="BIGINT" property="parentId" />
    <result column="parent_key" jdbcType="VARCHAR" property="parentKey" />
    <result column="type" jdbcType="TINYINT" property="type" />
    <result column="name" jdbcType="VARCHAR" property="name" />
    <result column="desc" jdbcType="VARCHAR" property="desc" />
    <result column="target_url" jdbcType="VARCHAR" property="targetUrl" />
    <result column="sort" jdbcType="INTEGER" property="sort" />
    <result column="status" jdbcType="TINYINT" property="status" />
    <result column="create_by" jdbcType="BIGINT" property="createBy" />
    <result column="modify_by" jdbcType="BIGINT" property="modifyBy" />
    <result column="created" jdbcType="TIMESTAMP" property="created" />
    <result column="last_update_time" jdbcType="TIMESTAMP" property="lastUpdateTime" />
  </resultMap>
  <sql id="Base_Column_List">
    <!--@mbg.generated-->
    id, parent_id, parent_key, `type`, `name`, `desc`, target_url, sort, `status`, create_by,
    modify_by, created, last_update_time
  </sql>
  <select id="selectMenusByUserId" resultMap="BaseResultMap">
        SELECT
          m.id,
          m.parent_id,
          m.parent_key,
          m.`type`,
          m.`name`,
          m.`desc`,
          m.target_url,
          m.sort,
          m.`status`,
          m.create_by,
          m.modify_by,
          m.created,
          m.last_update_time
        FROM sys_menu as m
                LEFT JOIN sys_role_menu AS rm ON rm.menu_id = m.id
                LEFT JOIN sys_user_role AS ur ON ur.role_id = rm.role_id
        WHERE
		        ur.user_id = #{userId}
  </select>
  <select id="selectMenusByRoleId" resultMap="BaseResultMap">
        SELECT
              m.id,
              m.parent_id,
              m.parent_key,
              m.`type`,
              m.`name`,
              m.`desc`,
              m.target_url,
              m.sort,
              m.`status`,
              m.create_by,
              m.modify_by,
              m.created,
              m.last_update_time
            FROM sys_menu AS m
                    LEFT JOIN sys_role_menu AS rm ON rm.menu_id = m.id
            WHERE
                    rm.role_id = #{roleId}
            ORDER BY m.id
  </select>
</mapper>
package com.dragonwu.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.dragonwu.domain.SysRole;

public interface SysRoleMapper extends BaseMapper<SysRole> {
    /**
     * 获取用户角色Code的实现
     * @param userId
     * @return
     */
    String getUserRoleCode(Long userId);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.dragonwu.mapper.SysRoleMapper">
    <resultMap id="BaseResultMap" type="com.dragonwu.domain.SysRole">
        <!--@mbg.generated-->
        <!--@Table sys_role-->
        <id column="id" jdbcType="BIGINT" property="id"/>
        <result column="name" jdbcType="VARCHAR" property="name"/>
        <result column="code" jdbcType="VARCHAR" property="code"/>
        <result column="description" jdbcType="VARCHAR" property="description"/>
        <result column="create_by" jdbcType="BIGINT" property="createBy"/>
        <result column="modify_by" jdbcType="BIGINT" property="modifyBy"/>
        <result column="status" jdbcType="TINYINT" property="status"/>
        <result column="created" jdbcType="TIMESTAMP" property="created"/>
        <result column="last_update_time" jdbcType="TIMESTAMP" property="lastUpdateTime"/>
    </resultMap>
    <sql id="Base_Column_List">
        <!--@mbg.generated-->
        id, `name`, code, description, create_by, modify_by, `status`, created, last_update_time
    </sql>
    <select id="getUserRoleCode" resultType="java.lang.String">
        SELECT
            r.`code`
        FROM
            sys_role AS r LEFT JOIN sys_user_role as ur on r.id = ur.role_id
        WHERE
          ur.user_id =#{userId}
    </select>
</mapper>

六、测试访问

 获取到token切正常,注意关键字。

登录至此实现!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值