AnonymousController.java 10.3 KB
package com.tianbo.warehouse.controller;

import com.alibaba.fastjson.JSON;

import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.google.code.kaptcha.impl.DefaultKaptcha;

import com.thoughtworks.xstream.core.util.Base64Encoder;
import com.tianbo.warehouse.controller.response.ResultJson;
import com.tianbo.warehouse.model.ROLE;
import com.tianbo.warehouse.model.Token;
import com.tianbo.warehouse.model.USERS;
import com.tianbo.warehouse.security.filter.JwtTokenUtil;
import com.tianbo.warehouse.service.PermissionService;
import com.tianbo.warehouse.service.RoleService;

import com.tianbo.warehouse.service.UserService;
import com.tianbo.warehouse.util.RedisUtils;

import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.imageio.ImageIO;

import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.*;

@Slf4j
@RestController()
@RequestMapping("/anonymous")
public class AnonymousController {

    @Autowired
    RoleService roleService;

    @Autowired
    private PermissionService permissionService;

    @Autowired
    RedisUtils redisUtils;

    @Autowired
    private  DefaultKaptcha captchaProducer;

    @Autowired
    RestTemplate restTemplate;

    @Value("${sso.url}")
    private String SSOUrl;

    @Value("${jwt.max-alive}")
    protected Integer jwtMaxAlive;

    @Autowired
    UserService userService;

    /**
     * SSO验证服务票据响应属性名
     */
    private static final String SERVICE_RESPONESE = "serviceResponse";
    private static final String AUTHENTICATION_SUCCESS = "authenticationSuccess";
    private static final String LOGIN_NAME = "LOGIN_NAME";
    private static final String ATTRIBUTES = "attributes";
    private static final String USER_ID = "USER_ID";

    /**
     * 配置匿名者可以访问的路由,并更新到redis,匿名者默认可以访问的role_name =ROLE_anonymous
     * 此方法会将所有符合权限组名=ROLE_anonymous的权限更新到redis中,供gateway调用判断权限
     * @return
     */
    @PostMapping("initAnonymousRoute")
    public ResultJson initAnonymousRoute(){
        List<ROLE> list = roleService.getROLE_anonymousPermList();
        String json = JSON.toJSONString(list);
        boolean result= redisUtils.set("ROLE_anonymous_routers", json,0);
        return result  ? new ResultJson("200","匿名者权限配置成功") :new ResultJson("500","匿名者权限配置失败");
    }

    /**
     * 生成验证码
     */
    @RequestMapping(value = "/randCode")
    public ResultJson getRandCode(){
        // 生成自定义验证码文字
        Random random = new Random();
        int num1 = random.nextInt(100);
        int num2 = random.nextInt(100);
        int sum = num1 + num2;
        System.out.println("验证码答案为: = " + sum);
        String capText = num1 + " + " + num2 + " = ";
        // 获取验证码上的文字
        //        String capText = captchaProducer.createText();
        //  将文件渲染到图片上
        BufferedImage bi = captchaProducer.createImage(capText);
        ByteArrayOutputStream outputStream = null;
        outputStream = new ByteArrayOutputStream();
        Base64Encoder encoder = new Base64Encoder();
        Map<String,Object> map = new HashMap<>();
        String verifyToken = "";
        try {
            verifyToken =  UUID.randomUUID().toString();
            redisUtils.set(Token.VERIFY_TOKEN_KEY + verifyToken,String.valueOf(sum),120);
            ImageIO.write(bi, "jpeg", outputStream);
            map.put("verifyImg","data:image/jpeg;base64,"+encoder.encode(outputStream.toByteArray()));
        } catch (IOException e) {
            e.printStackTrace();
            return new ResultJson("500","verify get error");
        }
        return new ResultJson("200","verify get ok",map,verifyToken);

    }

    @ApiOperation(value = "查询用户列表及信息", notes = "查询用户列表及单个用户信息")
    @RequestMapping("ssoTicket")
    public ResultJson ssoLogin(@RequestParam("ticket") String ticket,
                               @RequestParam("myWebLoginUrl") String myWebLoginUrl
    ){
        try {
            log.info("[SSO-AUTH-TICKET]-开始单点登录票据认证-[{}]",ticket);
            // 构建接口地址
            String url = SSOUrl+"?format=json&service="
                    + myWebLoginUrl
                    + "&ticket=" + ticket;

            // 使用RestTemplate调用接口
            RestTemplate restTemplate = new RestTemplate();
            /**
             * 单点登录认证返回实体类
             * {
             *   "serviceResponse" : {
             *     "authenticationSuccess" : {
             *       "user" : "zhangyf",
             *       "attributes" : {
             *         "isFromNewLogin" : [ false ],
             *         "authenticationDate" : [ 1.614564403617E9 ],
             *         "successfulAuthenticationHandlers" : [ "pwd" ],
             *         "USER_ID" : "8a0162a628aa4049a7840d75378f1a91",
             *         "USER_NAME" : "张炎锋",
             *         "extend" : [ ],
             *         "credentialType" : "UsernamePasswordCredential",
             *         "samlAuthenticationStatementAuthMethod" : "urn:oasis:names:tc:SAML:1.0:am:password",
             *         "ipTerritory" : "",
             *         "authenticationMethod" : "pwd",
             *         "equipType" : "pc",
             *         "clientIp" : "172.19.0.17",
             *         "isDefaultPwd" : "false",
             *         "longTermAuthenticationRequestTokenUsed" : [ false ],
             *         "LOGIN_NAME" : "zhangyf",
             *         "MOBILE" : "18739902467"
             *       }
             *     }
             *   }
             * },
             */
            ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class);
            String responseBody = responseEntity.getBody();

            try {
                JSONObject jsonObject = JSONObject.parseObject(responseBody);
                USERS user = parseSSOObject(jsonObject);
                if (StringUtils.isNotEmpty(user.getUsername())){
                    USERS loginUser = userService.loadByUsername(user.getUsername());
                    if (loginUser!=null && loginUser.getUserId()>-1){
                        log.info("[SSO-AUTH-TICKET]-从认证中心获取到用户[{}]信息,开始设置系统登录认证token",user.getUsername());
                        user.setUserId(loginUser.getUserId());
                        user.setUsername(loginUser.getUsername());
                        user.setUserface(loginUser.getUserface());
                        user.setUserId(loginUser.getUserId());
                        user.setRealname(loginUser.getRealname());
                        user.setCompanyId(loginUser.getCompanyId());
                        user.setCompanyName(loginUser.getCompanyName());
                        user.setCompanyInfo(loginUser.getCompanyInfo());
                        user.setUserStatus(loginUser.getUserStatus());
                        user.setState(loginUser.getState());
                    }else {
                        user.setPassword("sso");
                        user.setUserStatus(2);
                        user.setState(true);
                        userService.insertSelective(user);
                    }
                    //设置用户的TOKEN的有效时间,时间配置在配置文件中设置
                    int expirationSeconds = 3600*24*7;
                    String jwtToken = JwtTokenUtil.generateToken(user.getUsername(), jwtMaxAlive);
                    user.setToken(jwtToken);
                    //这里将登录成功的[user]对象数据写入redis缓存,KEY为token value为user的JSON对象
                    String json = JSON.toJSONString(loginUser);
                    redisUtils.set(jwtToken, json,expirationSeconds);
                    redisUtils.set(Token.USER_TOKEN_KEY + user.getUsername(),jwtToken,expirationSeconds);
                    Map<String,Object> menuMap =  permissionService.getUserMenus(user.getUserId());
                    return new ResultJson("200","单点登录认证成功",user);
                }
            } catch (JSONException e) {
                e.printStackTrace();
                log.error("[SSO-AUTH-TICKET-ERR]-单点登录票据解析异常",e);
                return new ResultJson("400","单点登录票据解析异常",e.getMessage());
            }
        }catch (Exception e){
            e.printStackTrace();
            log.error("[SSO-AUTH-TICKET-ERR]-单点登录票据认证异常",e);
        }
        return new ResultJson("401","单点登录票据认证失败");
    }

    /**
     * 解析单点认证返回的信息
     * @param ssoResp 返回实体类
     * @return 用户类
     */
    private USERS parseSSOObject(JSONObject ssoResp){
        USERS user = new USERS();
        // 根节点
        if (ssoResp.containsKey(SERVICE_RESPONESE)){
            JSONObject root = ssoResp.getJSONObject(SERVICE_RESPONESE);

            //成功节点
            if (root.containsKey(AUTHENTICATION_SUCCESS)){
                JSONObject auth = root.getJSONObject(AUTHENTICATION_SUCCESS);
                //用户名获取
                String userName = auth.getString("user");

                //用户其他属性
                JSONObject attributes = auth.getJSONObject(ATTRIBUTES);
                String loginName = attributes.getString(LOGIN_NAME);
                String userId = attributes.getString(USER_ID);
                String realName = attributes.getString("USER_NAME");
                log.info("[SSO-AUTH-TICKET-INFO]-用户:{}/{}",loginName,realName);

                user.setUsername(loginName);
//                user.setUserId(userId);
            }
        }
        return user;
    }
}