vue springboot 登录,

  vue springboot 登录,

  

目录

1.导入依赖2.JWTToken替换希罗原生令牌3。JWT代币工具类,提供JWT生成、校验、获取代币存储的信息4.JWTFilter请求拦截5.登录授权realm6.shiro配置7.登录网端8.异常处理9.缓存调用登录接口传过来的令牌10。请求头设置,带上令牌11。生产环境服务器配置公司开发的系统原先的用户信息是基于希罗会话进行管理,但是会议不适用于应用端,并且服务器重启后需要重新登录。需要改造将希罗和智威汤逊广告公司进行整合,实现通过代币登录。

 

  

1.导入依赖

依赖关系groupId com。auth 0/groupId artifact id Java-jwt/artifact id版本3 . 2 . 0/版本/依赖关系

 

  

2.JWTToken 替换 Shiro 原生 Token

导入org。阿帕奇。四郎。authc。authenticationtoken公共类JWTToken实现AuthenticationToken { //密钥私有字符串标记;公共JWTToken(字符串令牌){ this.token=token} @Override公共对象get principal(){ return token;公共对象getCredentials() {}

 

  

3.JWT token 工具类,提供JWT生成、校验、获取token存储的信息

导入com。验证0。jwt。jwt导入com。验证0。jwt。jwt验证器;导入com。验证0。jwt。算法。算法;导入com。验证0。jwt。例外情况。jwtdecodeexception导入com。验证0。jwt。接口。解码djwt导入com。hxkg。数据融合。控制器。飞行控制器;导入org。slf4j。记录者;导入org。SLF 4j。伐木工厂;导入org。spring框架。靴子。语境。属性。配置属性;导入org。spring框架。刻板印象。组件;导入Java。io。unsupportedencodingexception导入Java。util。日期;/** * JWT代币工具类* * @作者杨峰* @ Date 2019-09-17 */@配置属性(前缀= jwt )@组件公共类JWTUtil { private static Logger LOG=Logger factory。获取记录器(飞行控制器。类);//过期时间私有静态长过期;//秘钥私有静态字符串秘密;/** * 校验代币是否正确* * @param标记密钥* @返回是否正确*/公共静态布尔验证(字符串标记,字符串用户名){尝试{ //根据密码生成JWT效验器算法算法=算法HMAC256(秘密);jwt验证器验证器=jwt。要求(算法)。withClaim(用户名,用户名)。build();//效验代币

 

   verifier.verify(token); return true; } catch (UnsupportedEncodingException e) { return false; } } * 获得token中的信息无需secret解密也能获得 * @return token中包含的用户名 public static String getUsername(String token) { DecodedJWT jwt = JWT.decode(token); return jwt.getClaim("userName").asString(); } catch (JWTDecodeException e) { return null; * 获取用户id * @param token * @return public static String getUserId(String token) { return jwt.getClaim("userId").asString(); * 生成签名 * @param userName 用户名 * @param userId * @return 加密的token public static String sign(String userName, String userId) { Date date = new Date(System.currentTimeMillis() + expire * 1000); // 附带username信息 return JWT.create() .withClaim("userId", userId) .withExpiresAt(date) .sign(algorithm); } catch (Exception e) { public static Long getExpire() { return expire; public static void setExpire(Long expire) { JWTUtil.expire = expire; public static String getSecret() { return secret; public static void setSecret(String secret) { JWTUtil.secret = secret;}application.properties中增加:

  

#jwt token# token有效时长,7天,单位秒jwt.expire=604800jwt.secret=JWT_TOKEN_SHIRO

注意:jwt加解密的私钥使用配置的字符串而不使用用户登录密码的好处是防止用户密码被其他人修改后,用户操作系统此时再去校验token会发生token解析对不上的情况。

 

  

 

  

4.JWTFilter请求拦截

import org.apache.shiro.authz.UnauthorizedException;import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.http.HttpStatus;import org.springframework.web.bind.annotation.RequestMethod;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.net.URLEncoder;/** * jwt过滤器 * * @Author yangfeng * @Description preHandle->isAccessAllowed->isLoginAttempt->executeLogin * @Date 2019-09-18 * @Time 12:36 */public class JWTFilter extends BasicHttpAuthenticationFilter { private Logger logger = LoggerFactory.getLogger(this.getClass()); /** * 如果带有 token,则对 token 进行检查,否则直接通过 */ @Override protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws UnauthorizedException { //判断请求的请求头是否带上 "Token" if (isLoginAttempt(request, response)) { //如果存在,则进入 executeLogin 方法执行登入,检查 token 是否正确 try { executeLogin(request, response); return true; } catch (Exception e) { //token 错误 responseError(response, e.getMessage()); return false; //产生异常则阻止请求的继续执行 } } //如果请求头不存在 Token,则可能是执行登陆操作或者是游客状态访问,无需检查 token,直接返回 true return true; } /** * 判断用户是否想要登入。 * 检测 header 里面是否包含 Token */ @Override protected boolean isLoginAttempt(ServletRequest request, ServletResponse response) { HttpServletRequest req = (HttpServletRequest) request; String token = req.getHeader("Authorization"); return token != null; } /** * 执行登陆操作 */ @Override protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception { HttpServletRequest httpServletRequest = (HttpServletRequest) request; String token = httpServletRequest.getHeader("Authorization"); JWTToken jwtToken = new JWTToken(token); // 提交给realm进行登入,如果错误他会抛出异常并被捕获 getSubject(request, response).login(jwtToken); // 如果没有抛出异常则代表登入成功,返回true return true; } /** * 对跨域提供支持 */ @Override protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception { HttpServletRequest httpServletRequest = (HttpServletRequest) request; HttpServletResponse httpServletResponse = (HttpServletResponse) response; httpServletResponse.setHeader("Access-control-Allow-Origin", "*"); httpServletResponse.setHeader("Access-Control-Allow-Methods", "*"); httpServletResponse.setHeader("Access-Control-Allow-Headers", "*"); // 跨域时会首先发送一个option请求,这里我们给option请求直接返回正常状态 if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) { httpServletResponse.setStatus(HttpStatus.OK.value()); return false; } return super.preHandle(request, response); } /** * 请求异常跳转 */ private void responseError(ServletResponse response, String message) { try { HttpServletResponse httpServletResponse = (HttpServletResponse) response; //设置编码,否则中文字符在重定向时会变为空字符串 message = URLEncoder.encode(message, "UTF-8"); httpServletResponse.sendRedirect("/pc/login/noLogin?message=" + message); } catch (IOException e) { logger.error(e.getMessage()); } }}

executeLogin()方法中的getSubject(request, response).login(jwtToken)就是触发Shiro 登录操作。

 

  

 

  

5.登录授权realm

import com.auth0.jwt.exceptions.SignatureVerificationException;import com.auth0.jwt.exceptions.TokenExpiredException;import com.hxkg.datafusion.common.jwt.JWTToken;import com.hxkg.datafusion.common.jwt.JWTUtil;import com.hxkg.datafusion.entity.customized.RoleAO;import com.hxkg.datafusion.entity.customized.UserAO;import com.hxkg.datafusion.entity.customized.VUserPrivilegeAO;import com.hxkg.datafusion.service.IRoleService;import com.hxkg.datafusion.service.IUserService;import com.hxkg.datafusion.service.IVUserPrivilegeService;import org.apache.shiro.SecurityUtils;import org.apache.shiro.authc.AuthenticationException;import org.apache.shiro.authc.AuthenticationInfo;import org.apache.shiro.authc.AuthenticationToken;import org.apache.shiro.authc.SimpleAuthenticationInfo;import org.apache.shiro.authz.AuthorizationInfo;import org.apache.shiro.authz.SimpleAuthorizationInfo;import org.apache.shiro.realm.AuthorizingRealm;import org.apache.shiro.subject.PrincipalCollection;import org.springframework.stereotype.Service;import org.springframework.util.CollectionUtils;import org.springframework.util.StringUtils;import javax.annotation.Resource;import java.util.List;/** * 登录授权realm * * @author yangfeng * @date 2019.6.21 */@Servicepublic class ShiroRealm extends AuthorizingRealm { @Resource private IRoleService roleService; @Resource private IVUserPrivilegeService vUserPrivilegeService; @Resource private IUserService userService; @Override public boolean supports(AuthenticationToken token) { return token instanceof JWTToken; } /** * 为当前登录用户授予角色和权限 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { String username = JWTUtil.getUsername(principals.getPrimaryPrincipal().toString()); SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); // 根据登录名获取登用户信息 if (!StringUtils.isEmpty(username)) { //设置用户角色 ServiceResult<List<RoleAO>> rolesResult = roleService.getRolesByUserName(username); if (rolesResult != null && rolesResult.isSucceed() && !CollectionUtils.isEmpty(rolesResult.getData())) { for (RoleAO role : rolesResult.getData()) { authorizationInfo.addRole(role.getName()); } } //设置权限 List<VUserPrivilegeAO> privileges = vUserPrivilegeService.queryPrivilegeByUserName(username); if (!CollectionUtils.isEmpty(privileges)) { for (VUserPrivilegeAO privilege : privileges) { if (privilege == null StringUtils.isEmpty(privilege.getPrivilegecode())) { continue; } //权限操作代码 authorizationInfo.addStringPermission(privilege.getPrivilegecode()); } } return authorizationInfo; } return null; } /** * 验证当前登录的用户 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) throws AuthenticationException { String token = (String) auth.getCredentials(); // 解密获得username,用于和数据库进行对比 String username = JWTUtil.getUsername(token); if (StringUtils.isEmpty(username)) { throw new AuthenticationException("token错误!"); } UserAO user = userService.getUserByName(username); if (user == null) { throw new AuthenticationException("用户不存在!"); } if (Constant.DISABLE.equals(user.getEnabled())) { throw new AuthenticationException("账号已被禁用!"); } try { if (JWTUtil.verify(token, username)) { return new SimpleAuthenticationInfo(token, token, getName()); } else { throw new AuthenticationException("token认证失败!"); } } catch (TokenExpiredException e) { throw new AuthenticationException("token已过期!"); } catch (SignatureVerificationException e) { throw new AuthenticationException("密码不正确!"); } } /** * 清除登陆用户授权信息缓存. */ public void clearCached() { this.clearCachedAuthorizationInfo(SecurityUtils.getSubject().getPrincipals()); } /** * 超级管理员不做权限的判断,自动拥有所有权限 * * @param principals * @param permission * @return */ @Override public boolean isPermitted(PrincipalCollection principals, String permission) { String username = JWTUtil.getUsername(principals.getPrimaryPrincipal().toString()); //Constant常量文件配置: //public static String SYSTEM_SUPER_ADMIN = "admin";系统超级管理员 return Constant.SYSTEM_SUPER_ADMIN.equals(username) super.isPermitted(principals, permission); } @Override public boolean hasRole(PrincipalCollection principals, String roleIdentifier) { String username = JWTUtil.getUsername(principals.getPrimaryPrincipal().toString()); return Constant.SYSTEM_SUPER_ADMIN.equals(username) super.hasRole(principals, roleIdentifier); }}

 

  

6.shiro配置

import com.hxkg.datafusion.common.jwt.JWTFilter;import com.hxkg.datafusion.util.ShiroRealm;import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;import org.apache.shiro.mgt.DefaultSubjectDAO;import org.apache.shiro.spring.LifecycleBeanPostProcessor;import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;import org.apache.shiro.spring.web.ShiroFilterFactoryBean;import org.apache.shiro.web.mgt.DefaultWebSecurityManager;import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.DependsOn;import javax.servlet.Filter;import java.util.HashMap;import java.util.Map;/** * shiro配置 * * @author yangfeng * @date 2019.7.14 */@Configurationpublic class ShiroConfig { @Bean("securityManager") public DefaultWebSecurityManager securityManager(ShiroRealm shiroRealm) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); // 使用自己的realm securityManager.setRealm(shiroRealm); /* * 关闭shiro自带的session,详情见文档 * http://shiro.apache.org/session-management.html#SessionManagement-StatelessApplications%28Sessionless%29 */ DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO(); DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator(); defaultSessionStorageEvaluator.setSessionStorageEnabled(false); subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator); securityManager.setSubjectDAO(subjectDAO); return securityManager; } @Bean("shiroFilter") public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager) { ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean(); // 添加自己的过滤器并且取名为jwt Map<String, Filter> filterMap = new HashMap<>(); filterMap.put("jwt", new JWTFilter()); factoryBean.setFilters(filterMap); factoryBean.setSecurityManager(securityManager); factoryBean.setUnauthorizedUrl("/401"); /* * 自定义url规则 * http://shiro.apache.org/web.html#urls- */ Map<String, String> filterRuleMap = new HashMap<>(); filterRuleMap.put("/pc/login/doLogin", "anon"); filterRuleMap.put("/pc/login/logout", "anon"); filterRuleMap.put("/pc/login/noLogin", "anon"); filterRuleMap.put("/**", "authc"); // 所有请求通过我们自己的JWT Filter filterRuleMap.put("/**", "jwt"); factoryBean.setLoginUrl("/pc/login/noLogin");//没有登录的用户请求需要登录的资源时自动跳转到该路径 factoryBean.setUnauthorizedUrl("/pc/login/unauthorized");//没有权限默认跳转 factoryBean.setFilterChainDefinitionMap(filterRuleMap); return factoryBean; } /** * 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证 * @param securityManager * @return */ /** * 下面的代码是添加注解支持 */ @Bean @DependsOn("lifecycleBeanPostProcessor") public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); defaultAdvisorAutoProxyCreator.setProxyTargetClass(true); return defaultAdvisorAutoProxyCreator; } @Bean public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { return new LifecycleBeanPostProcessor(); } @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) { AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor(); advisor.setSecurityManager(securityManager); return advisor; }}除了登录doLogin、退出logout、没有登录跳转登录noLogin方法外,其他所有请求通过我们自己的JWT Filter。

 

  

7.登录web端

import com.hxkg.datafusion.common.jwt.JWTUtil;import com.hxkg.datafusion.entity.customized.UserAO;import com.hxkg.datafusion.entity.customized.VUserPrivilegeAO;import com.hxkg.datafusion.service.IUserService;import com.hxkg.datafusion.service.IVUserPrivilegeService;import com.hxkg.datafusion.util.*;import org.apache.commons.lang3.StringUtils;import org.apache.shiro.SecurityUtils;import org.apache.shiro.subject.Subject;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.web.bind.annotation.*;import javax.annotation.Resource;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.util.Date;import java.util.List;/** * 登录 * * @author yangfeng * @date 2019-07-11 16:02 */@RestController@RequestMapping(value = "pc/login")public class LoginController { private static Logger LOG = LoggerFactory.getLogger(LoginController.class); @Resource private IUserService userService; @Resource private IVUserPrivilegeService vUserPrivilegeService; /** * 未登陆认证 * * @param message * @return */ @RequestMapping(value = "noLogin", method = {RequestMethod.GET, RequestMethod.POST}) @ResponseBody public Object noLogin(String message) { ServiceResult<String> genResult = ServiceResultHelper.genResult(false, Constant.NO_AUTHENTICATION, StringUtils.isNotEmpty(message) ? message : "用户登录信息已失效,请重新登录后再试。", null); return genResult; } /** * 未授权 * * @return */ @RequestMapping(value = "unauthorized", method = {RequestMethod.GET, RequestMethod.POST}) public Object unauthorized() { return ServiceResultHelper.genResult(false, Constant.ErrorCode.PERMISSION_DENIED_CODE, Constant.ErrorCode.PERMISSION_DENIED_MSG, null); } /** * 登录操作 * * @param username * @param password * @param request * @param response * @return */ @RequestMapping(value = "doLogin", method = {RequestMethod.GET, RequestMethod.POST}) public Object doLogin(String username, String password, Boolean rememberMe, HttpServletRequest request, HttpServletResponse response) { ServiceResult<UserAO> genResult; // 获取盐值 String salt; UserAO loginUser = userService.getUserByName(username); if (loginUser == null) { genResult = ServiceResultHelper.genResult(false, Constant.ErrorCode.USER_NOT_EXIST_ERROR, Constant.ErrorCode.USER_NOT_EXIST_ERROR_MSG, null); return genResult; } if (Constant.DISABLE.equals(loginUser.getEnabled())) { genResult = ServiceResultHelper.genResult(false, Constant.ErrorCode.USER_DISABLE_ERROR, Constant.ErrorCode.USER_DISABLE_ERROR_MSG, null); return genResult; } salt = loginUser.getSalt(); password = MD5Util.MD5Encode(password + salt); UserAO user = userService.getUserByNameAndPwd(username, password); if (user != null) { genResult = ServiceResultHelper.genResult(true, Constant.SUCCESS, "登录成功", user); //获取权限 List<VUserPrivilegeAO> userPrivileges = vUserPrivilegeService.queryPrivilegeByUserName(username); user.setPrivileges(userPrivileges); //更新登录信息 user.setLastLoginTime(DateTimeUtil.format(new Date(), DateTimeUtil.YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)); user.setLastLoginIp(IPUtil.getClientIp(request)); userService.saveOrUpdate(user); genResult.setAdditionalProperties("token", JWTUtil.sign(username, user.getId())); } else { genResult = ServiceResultHelper.genResult(false, Constant.ErrorCode.PASSWORD_ERROR, Constant.ErrorCode.PASSWORD_ERROR_MSG, null); } return genResult; } /** * 退出登录 * * @param request * @param response * @return */ @RequestMapping(value = "logout", method = {RequestMethod.GET, RequestMethod.POST}) public Object logout(HttpServletRequest request, HttpServletResponse response) { Subject currentUser = SecurityUtils.getSubject(); currentUser.logout(); CookieUtil cookieUtil = new CookieUtil(request, response, 0); cookieUtil.deleteCookie(Constant.SESSION_CURRENT_USER); cookieUtil.deleteCookie("JSESSIONID"); ServiceResult<Object> ret = new ServiceResult<Object>(); ret.setMsg("退出登录成功"); ret.setCode(Constant.SUCCESS); ret.setData(null); ret.setSucceed(true); return ret; }}

登录完成一系列的检查,成功后创建jwt token。

 

  

 

  

8.异常处理

import com.hxkg.datafusion.util.Constant;import com.hxkg.datafusion.util.ServiceResultHelper;import org.apache.shiro.authz.UnauthenticatedException;import org.apache.shiro.authz.UnauthorizedException;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.web.bind.annotation.ControllerAdvice;import org.springframework.web.bind.annotation.ExceptionHandler;import org.springframework.web.bind.annotation.ResponseBody;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;/** * 异常处理 * * @author yangfeng * @date 2019-09-11 */@ControllerAdvicepublic class WebExceptionHandler { private static Logger LOG = LoggerFactory.getLogger(WebExceptionHandler.class); @ExceptionHandler(UnauthorizedException.class) @ResponseBody public Object handleUnauthorizedException(Exception ex, HttpServletRequest request, HttpServletResponse response) { LOG.error("{}", ex.getMessage()); return ServiceResultHelper.genResult(false, Constant.ErrorCode.PERMISSION_DENIED_CODE, Constant.ErrorCode.PERMISSION_DENIED_MSG, null); } @ExceptionHandler(UnauthenticatedException.class) @ResponseBody public Object handleUnauthenticatedException(Exception ex, HttpServletRequest request, HttpServletResponse response) { LOG.error("{}", ex.getMessage()); return ServiceResultHelper.genResult(false, Constant.ErrorCode.INVALID_LOGIN_CODE, Constant.ErrorCode.INVALID_LOGIN_MSG, null); } @ExceptionHandler(Exception.class) @ResponseBody public Object handleException(Exception ex, HttpServletRequest request, HttpServletResponse response) { LOG.error("{}", ex.getMessage()); return ServiceResultHelper.genResult(false, Constant.ErrorCode.SERVER_ERROR_CODE, Constant.ErrorCode.SERVER_ERROR_MSG, null); }}

处理未登录、未授权等异常,返回相应的代码,方便前端捕获跳转登录页面,或者作出提示,而不会直接抛出服务器异常导致提示不够明确。

 

  到此后端已经全部写完。接下来是vue部分。

  

 

  

9.缓存调用登录接口传过来的token

localStorage.setItem(token, token);

 

  

10.请求头设置,带上token

//封装请求function xAxios(options) { let opts = {...options}; let token = localStorage.getItem(token) if (token) { opts.headers[Authorization] = token }

 

  

11.生产环境nginx配置

因为后端jetFilter登录异常会进行重定向,所以nginx需要加上前端的代理配置。

 

  

 

  到此这篇关于vue+springboot+shiro+jwt实现登

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: