使用Jwt实现简单登陆效果

991 阅读4分钟

简介:

​ 在企业发展初期,企业使⽤的系统很少,通常⼀个或者两个,每个系统都有⾃⼰的登录模块,运营⼈员每天⽤⾃⼰的账号登录,很⽅便。 ​ 但随着企业的发展,⽤到的系统随之增多,运营⼈员在操作不同的系统时,需要多次登录,⽽且每个系统的账号都不⼀样,这对于运营⼈员来说,很不⽅便。于是,就想到是不是可以在⼀个系统登录,其他系统就不⽤登录了呢?这就是单点登录要解决的问题。 ​ 单点登录英⽂全称Single Sign On,简称就是SSO。它的解释是:在多个应⽤系统中,只需要登录⼀次,就可以访问其他相互信任的应⽤系统。

流程:

如图所示,图中有四个系统,分别是SSO系统,Application1,Application2,Application3。在Application1、Application2、Application3这三个系统中没有登陆模块,只有SSO中才有登陆模块,当你要登陆的时候,会跳转到SSO模块,登陆成功后会跳转到对应的功能模块中。

技术实现:

第⼀步:引⼊我们需要的依赖:

<!-- jwt -->
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.4.1</version>
        </dependency>
		 <!-- shiro -->
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-spring</artifactId>
        <version>1.4.0</version>
    </dependency>

    <!-- lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>

第⼆步:我们需要⼀个User类:

User

public class User {

    private String username;

    private String password;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

第三步:我们需要认证的基本类:

JWTToken

 @Data
 public class JWTToken implements AuthenticationToken {

private String token;

private String expireAt;

@Override
public Object getPrincipal() {

    return token;

}

@Override
public Object getCredentials() {

    return token;

}

public JWTToken(String token) {
    this.token = token;
}

public JWTToken(String token, String expireAt) {
    this.token = token;
    this.expireAt = expireAt;
}

}

JWTUtil

/**
 * @author Lenovo
 */
public class JWTUtil {

    private static final Logger LOGGER = LoggerFactory.getLogger(JWTUtil.class);

    private static final Integer EXPIRE_TIME = SpringContextUtil.getBean(E17Properties.class).getJwtTimeOut() * 1000;
    
    /**
     * 校验token是否正确
     *
     * @param token
     * @param username
     * @param password
     * @return
     */
    public static boolean verify(String token, String username, String password) {
    
    try {

            Algorithm algorithm = Algorithm.HMAC256(password);

            JWTVerifier verifier = JWT.require(algorithm).withClaim("username", username).build();

            LOGGER.info("token is valid");

            return true;

        } catch (Exception e) {

            LOGGER.error("token is invalid{}", e.getMessage());

            return false;
        }
    }
    
    /**
     * 根据token获取用户名
     *
     * @param token
     * @return
     */
    public static String getUserName(String token) {

        try {

            DecodedJWT decode = JWT.decode(token);

            return decode.getClaim("username").asString();

        } catch (JWTDecodeException e) {

            LOGGER.error("error:{}", e.getMessage());

            return null;
        }
    }
    
    /**
     * 生成token
     *
     * @param username
     * @param password
     * @return
     */
    public static String sign(String username, String password) {

        try {

            username = StringUtils.lowerCase(username);

            Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);

            Algorithm algorithm = Algorithm.HMAC256(password);

            return JWT.create().withClaim("username", username).withExpiresAt(date).sign(algorithm);

        } catch (Exception e) {

            LOGGER.error("error:{}", e.getMessage());

            return null;
        }
    }
}   

第四步:⾃定义的Properties:(主要⽤户设置⼀些基本的参数)

​ 先上配置文件:

E17Properties.properties

#自定义
e17.auth.anonUrl= /login

e17.auth.jwtTimeOut=3600

E17Properties

/**
 * @author Lenovo
 */
@SpringBootConfiguration
@ConfigurationProperties(prefix = "e17.auth")
@PropertySource(value = "classpath:E17Properties.properties")
public class E17Properties {

/**
     * 免认证URl
     */
    private String anonUrl;
    
    /**
     * token有效期时间为1天
     */
    private Integer jwtTimeOut = 86400;
    
     public String getAnonUrl() {
        return anonUrl;
    }

    public void setAnonUrl(String anonUrl) {
        this.anonUrl = anonUrl;
    }

    public Integer getJwtTimeOut() {
        return jwtTimeOut;
    }

    public void setJwtTimeOut(Integer jwtTimeOut) {
        this.jwtTimeOut = jwtTimeOut;
    }
}        

第五步:工具类:

MD5Util:

/**
 * @author Lenovo
 */
public class MD5Util {

    protected MD5Util(){

    }

    private static final String ALGORITH_NAME = "md5";

    private static final int HASH_ITERATIONS = 2;

    public static String encrypt(String password) {
        return new SimpleHash(ALGORITH_NAME, password, ByteSource.Util.bytes(password), HASH_ITERATIONS).toHex();
    }

    public static String encrypt(String username, String password) {
        return new SimpleHash(ALGORITH_NAME, password, ByteSource.Util.bytes(username.toLowerCase() + password),
                HASH_ITERATIONS).toHex();
    }

}

SpringContextUtil

/**
 * @author Lenovo
 */
@Component
public class SpringContextUtil implements ApplicationContextAware {

private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

        SpringContextUtil.applicationContext = applicationContext;
    }

    public static Object getBean(String name) {
        return applicationContext.getBean(name);
    }
    public static <T> T getBean(Class<T> clazz){
        return applicationContext.getBean(clazz);
    }

    public static <T> T getBean(String name, Class<T> requiredType) {
        return applicationContext.getBean(name, requiredType);
    }

    public static boolean containsBean(String name) {
        return applicationContext.containsBean(name);
    }

    public static boolean isSingleton(String name) {
        return applicationContext.isSingleton(name);
    }

    public static Class<?> getType(String name) {
        return applicationContext.getType(name);
    }
}

ApiResponse

/**
 * @author Lenovo
 */
public class ApiResponse extends HashMap<String, Object> {


    public ApiResponse message(String msg) {

        this.put("msg", msg);

        return this;
    }

    public ApiResponse data(Object data) {

        this.put("data", data);

        return this;
    }

    @Override
    public ApiResponse put(String key, Object value) {

        super.put(key, value);

        return this;
    }
}

CookieUtils

package com.e17.common.util;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;

/**
 * Cookie工具类
 * @author Lenovo
 */
public class CookieUtils {

    static final Logger logger = LoggerFactory.getLogger(CookieUtils.class);

    /**
     * 得到Cookie的值, 不编码
     *
     * @param request
     * @param cookieName
     * @return
     */
    public static String getCookieValue(HttpServletRequest request, String cookieName) {
        return getCookieValue(request, cookieName, false);
    }

    /**
     * 得到Cookie的值,
     *
     * @param request
     * @param cookieName
     * @return
     */
    public static String getCookieValue(HttpServletRequest request, String cookieName, boolean isDecoder) {
        Cookie[] cookieList = request.getCookies();
        if (cookieList == null || cookieName == null){
            return null;
        }
        String retValue = null;
        try {
            for (int i = 0; i < cookieList.length; i++) {
                if (cookieList[i].getName().equals(cookieName)) {
                    if (isDecoder) {
                        retValue = URLDecoder.decode(cookieList[i].getValue(), "UTF-8");
                    } else {
                        retValue = cookieList[i].getValue();
                    }
                    break;
                }
            }
        } catch (UnsupportedEncodingException e) {
            logger.error("Cookie Decode Error.", e);
        }
        return retValue;
    }

    /**
     * 得到Cookie的值,
     *
     * @param request
     * @param cookieName
     * @return
     */
    public static String getCookieValue(HttpServletRequest request, String cookieName, String encodeString) {
        Cookie[] cookieList = request.getCookies();
        if (cookieList == null || cookieName == null){
            return null;
        }
        String retValue = null;
        try {
            for (int i = 0; i < cookieList.length; i++) {
                if (cookieList[i].getName().equals(cookieName)) {
                    retValue = URLDecoder.decode(cookieList[i].getValue(), encodeString);
                    break;
                }
            }
        } catch (UnsupportedEncodingException e) {
            logger.error("Cookie Decode Error.", e);
        }
        return retValue;
    }

    /**
     * 生成cookie,并指定编码
     * @param request 请求
     * @param response 响应
     * @param cookieName name
     * @param cookieValue value
     * @param encodeString 编码
     */
    public static final void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName, String cookieValue, String encodeString) {
        setCookie(request,response,cookieName,cookieValue,null,encodeString, null);
    }

    /**
     * 生成cookie,并指定生存时间
     * @param request 请求
     * @param response 响应
     * @param cookieName name
     * @param cookieValue value
     * @param cookieMaxAge 生存时间
     */
    public static final void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName, String cookieValue, Integer cookieMaxAge) {
        setCookie(request,response,cookieName,cookieValue,cookieMaxAge,null, null);
    }

    /**
     * 设置cookie,不指定httpOnly属性
     */
    public static final void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName, String cookieValue, Integer cookieMaxAge, String encodeString) {
        setCookie(request,response,cookieName,cookieValue,cookieMaxAge,encodeString, null);
    }

    /**
     * 设置Cookie的值,并使其在指定时间内生效
     *
     * @param cookieMaxAge
     *            cookie生效的最大秒数
     */
    public static final void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName, String cookieValue, Integer cookieMaxAge, String encodeString, Boolean httpOnly) {
        try {
            if(StringUtils.isBlank(encodeString)) {
                encodeString = "utf-8";
            }

            if (cookieValue == null) {
                cookieValue = "";
            } else {
                cookieValue = URLEncoder.encode(cookieValue, encodeString);
            }
            Cookie cookie = new Cookie(cookieName, cookieValue);
            if (cookieMaxAge != null && cookieMaxAge > 0)
                cookie.setMaxAge(cookieMaxAge);
            if (null != request)// 设置域名的cookie
                cookie.setDomain(getDomainName(request));
            cookie.setPath("/");

            if(httpOnly != null) {
                cookie.setHttpOnly(httpOnly);
            }
            response.addCookie(cookie);
        } catch (Exception e) {
            logger.error("Cookie Encode Error.", e);
        }
    }

    /**
     * 得到cookie的域名
     */
    private static final String getDomainName(HttpServletRequest request) {
        String domainName = null;

        String serverName = request.getRequestURL().toString();
        if (serverName == null || serverName.equals("")) {
            domainName = "";
        } else {
            serverName = serverName.toLowerCase();
            serverName = serverName.substring(7);
            final int end = serverName.indexOf("/");
            serverName = serverName.substring(0, end);
            final String[] domains = serverName.split("\\.");
            int len = domains.length;
            if (len > 3) {
                // www.xxx.com.cn
                domainName = domains[len - 3] + "." + domains[len - 2] + "." + domains[len - 1];
            } else if (len <= 3 && len > 1) {
                // xxx.com or xxx.cn
                domainName = domains[len - 2] + "." + domains[len - 1];
            } else {
                domainName = serverName;
            }
        }

        if (domainName != null && domainName.indexOf(":") > 0) {
            String[] ary = domainName.split("\\:");
            domainName = ary[0];
        }
        return domainName;
    }
}

实际操作:

定义AuthController:

AuthController

/**
 * 授权Controller
 *
 * @author Lenovo
 */
@Controller
@Validated
public class AuthController {

@Autowired(required = false)
    private AuthService authService;

    private static final Logger LOGGER = LoggerFactory.getLogger(AuthController.class);
    
    /**
     * 登录授权
     *
     * @param username
     * @param password
     * @return
     */
    @PostMapping("accredit")
    public ResponseEntity<ApiResponse> accredit(@RequestParam(value = "username", required = true) String username,
                                                @RequestParam(value = "password", required = true) String password,
                                                HttpServletRequest request, HttpServletResponse response) {
     
     ApiResponse apiResponse = this.authService.accredit(username, password, request, response);

        return ResponseEntity.ok(apiResponse);
    }
                                                
     /**
     * 登录校验接口
     *
     * @param token
     * @return
     */
    @PostMapping("verify")
    public ResponseEntity<ApiResponse> verify(@RequestParam("token") String token) {

        String userName = JWTUtil.getUserName(token);

        return ResponseEntity.ok(new ApiResponse().message(userName));
    }
}                              

定义AuthService

AuthService

/**
 * @author Lenovo
 */
public interface AuthService {

    // 登录授权
    ApiResponse accredit(String username, String password, HttpServletRequest request, HttpServletResponse response);
}

定义AuthServiceImpl

AuthServiceImpl

/**
 * 授权Service
 *
 * @author Lenovo
 */
@Service
public class AuthServiceImpl implements AuthService {

    @Autowired(required = false)
    private E17Properties e17Properties;
    
    /**
     * 登录授权
     *
     * @param username
     * @param password
     * @return
     */
    @Override
    public ApiResponse accredit(String username, String password, HttpServletRequest request, HttpServletResponse response) {
      
        String token = null;

        try {
            // 存在
            // 生成token
            token = JWTUtil.sign(username, password);

            // 将其保存到Cookie中
            CookieUtils.setCookie(request, response, "TOKEN", token, e17Properties.getJwtTimeOut());
            // 返回token
            return new ApiResponse().data(token).message("登录成功");

        } catch (Exception e) {

            e.printStackTrace();

            return new ApiResponse().message("服务器错误").data(null);
        }
        
            }
}        

2020-03-14 20:54:55 星期六 到这里我们的代码就完了,是不是很简短呢。。。。。。 有问题欢迎在评论区评论,感谢你的阅读。。。。