当前位置 主页 > 服务器问题 > Linux/apache问题 >

    Spring boot整合shiro+jwt实现前后端分离

    栏目:Linux/apache问题 时间:2019-12-16 22:47

    本文实例为大家分享了Spring boot整合shiro+jwt实现前后端分离的具体代码,供大家参考,具体内容如下

    这里内容很少很多都为贴的代码,具体内容我经过了看源码和帖子加了注释。帖子就没用太多的内容

    先下载shiro和jwt的jar包

    <!-- shiro包 -->
    <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-spring</artifactId>
      <version>1.4.0</version>
    </dependency>
    <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-ehcache</artifactId>
      <version>1.4.0</version>
    </dependency>
    <!--JWT依赖-->
    <!--JWT-->
    <dependency>
      <groupId>com.auth0</groupId>
      <artifactId>java-jwt</artifactId>
      <version>3.4.0</version>
    </dependency>
    <!--JJWT-->
    <dependency>
       <groupId>io.jsonwebtoken</groupId>
       <artifactId>jjwt</artifactId>
       <version>0.9.0</version>
    </dependency>

    创建shiro的自定义的Realm

    代码如下:

    package com.serverprovider.config.shiro.userRealm;
     
     
    import com.spring.common.auto.autoUser.AutoUserModel;
    import com.spring.common.auto.autoUser.extend.AutoModelExtend;
    import com.serverprovider.config.shiro.jwt.JWTCredentialsMatcher;
    import com.serverprovider.config.shiro.jwt.JwtToken;
    import com.serverprovider.service.loginService.LoginServiceImpl;
    import com.util.Redis.RedisUtil;
    import com.util.ReturnUtil.SecretKey;
    import com.util.encryption.JWTDecodeUtil;
    import io.jsonwebtoken.Claims;
    import org.apache.log4j.Logger;
    import org.apache.shiro.authc.*;
    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.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.ExceptionHandler;
     
    import java.util.HashSet;
    import java.util.List;
    import java.util.Set;
     
    public class UserRealm extends AuthorizingRealm {
     
      private Logger logger = Logger.getLogger(UserRealm.class);
     
     
      @Autowired private LoginServiceImpl loginService;
     
     
      public UserRealm(){
        //这里使用我们自定义的Matcher验证接口
        this.setCredentialsMatcher(new JWTCredentialsMatcher());
      }
     
      /**
       * 必须重写此方法,不然Shiro会报错
       */
      @Override
      public boolean supports(AuthenticationToken token) {
        return token instanceof JwtToken;
      }
     
      /**
       * shiro 身份验证
       * @param token
       * @return boolean
       * @throws AuthenticationException 抛出的异常将有统一的异常处理返回给前端
       *
       */
      @Override
      protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)throws AuthenticationException {
        /**
         * AuthenticationToken
         * JwtToken重写了AuthenticationToken接口 并创建了一个接口token的变量
         *  因为在filter我们将token存入了JwtToken的token变量中
         *  所以这里直接getToken()就可以获取前端传递的token值
         */
          String JWTtoken = ((JwtToken) token).getToken();
        /**
         * Claims对象它最终是一个JSON格式的对象,任何值都可以添加到其中
         * token解密 转换成Claims对象
         */
           Claims claims = JWTDecodeUtil.parseJWT(JWTtoken, SecretKey.JWTKey);
          
        /**
         *  根据JwtUtil加密方法加入的参数获取数据
         *  查询数据库获得对象
         *  如为空:抛出异常
         *  如验证失败抛出 AuthorizationException
         */
          String username = claims.getSubject();
          String password = (String) claims.get("password");
          AutoModelExtend principal = loginService.selectLoginModel(username,password);
          return new SimpleAuthenticationInfo(principal, JWTtoken,"userRealm");
      }
     
     
      @Override
      protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        SimpleAuthorizationInfo info = null;
        /**
         * PrincipalCollection对象
         * 文档里面描述:返回从指定的Realm 仅作为Collection 返回的单个Subject的对象,如果没有来自该领域的任何对象,则返回空的Collection。
         * 在登录接口放入权限注解返回的错误信息:Subject.login(AuthenticationToken)或SecurityManager启用'Remember Me'功能后成功自动获取这些标识主体
         * 当调用Subject.login()方法成功后 PrincipalCollection会自动获得该对象 如没有认证过或认证失败则返回空的Collection并抛出异常
         * getPrimaryPrincipal():返回在应用程序范围内使用的主要对象,以唯一标识拥有帐户。
         */
        Object principal = principals.getPrimaryPrincipal();
        /**
         * 得到身份对象
         * 查询该用户的权限信息
         */
        AutoUserModel user = (AutoUserModel) principal;
        List<String> roleModels = loginService.selectRoleDetails(user.getId());
        try {
        /**
         * 创建一个Set,来放置用户拥有的权限
         * 创建 SimpleAuthorizationInfo, 并将办好权限列表的Set放入.
         */
        Set<String> rolesSet = new HashSet();
        for (String role : roleModels) {
          rolesSet.add(role);
        }
        info = new SimpleAuthorizationInfo();
        info.setStringPermissions(rolesSet);  // 放入权限信息
      }catch (Exception e){
        throw new AuthenticationException("授权失败!");
      }
        return info;
      }
    }