`
wj596
  • 浏览: 26622 次
  • 性别: Icon_minigender_1
  • 来自: 安徽
社区版块
存档分类
最新评论

shiro jwt 构建无状态分布式鉴权体系

阅读更多

一:JWT

1、令牌构造

JWT(json web token)是可在网络上传输的用于声明某种主张的令牌(token),以JSON 对象为载体的轻量级开放标准(RFC 7519)。

一个JWT令牌的定义包含头信息、荷载信息、签名信息三个部分:

Header//头信息
{
    "alg": "HS256",//签名或摘要算法
    "typ": "JWT"//token类型
}
Playload//荷载信息
{
    "iss": "token-server",//签发者
    "exp ": "Mon Nov 13 15:28:41 CST 2017",//过期时间
    "sub ": "wangjie",//用户名
    "aud": "web-server-1"//接收方,
    "nbf": "Mon Nov 13 15:40:12 CST 2017",//这个时间之前token不可用
    "jat": "Mon Nov 13 15:20:41 CST 2017",//签发时间
    "jti": "0023",//令牌id标识
    "claim": {“auth”:”ROLE_ADMIN”}//访问主张
}
Signature//签名信息
签名或摘要算法(
    base64urlencode(Header),
    Base64urlencode(Playload),
    secret-key
)

按照JWT规范,对这个令牌定义进行如下操作:

base64urlencode(Header)
+"."+
base64urlencode(Playload)
+"."+
signature(
    base64urlencode(Header)
    +"."+
    base64urlencode(Playload)
    ,secret-key
)

形成一个完整的JWT:
eyJhbGciOiJIUzUxMiIsInppcCI6IkRFRiJ9.eNqqVspMLFGyMjQ1NDA1tTA0NNRRKi5NUrJSKk_MS8_KTFXSUUqtKEAoMDKsBQAAAP__.dGLe7BVECKzQ_utZJqk4hbcBZthNhohuEjjue98vmpQSGn_9cCYHq7lPIfwKubW8M553F8Uhk933EJwgI5vbLQ

需要注意的是:

1:荷载信息(Playload)中的属性可以根据情况进行设置,不要求必须全部填写。

2:由token的生成方式发现,Header和Playload仅仅是base64编码,通过base64解码之后可见,基本相当于是明文传输,所以应避免敏感信息放入Playload。

2、令牌特点

紧凑性:体积较小、意味着传输速度快,可以作为POST参数或放置在HTTP头。

自包含性:有效的负载包含用户鉴权所需所有信息,避免多次查询数据库。

安全性:支持对称和非对称方式(HMAC、RSA)进行消息摘要签名。

标准化:开放标准,多语言支持,跨平台。

3、适用场景

1:无状态、分布式鉴权,比如rest api系统、微服务系统。

2:方便解决跨域授权的问题,比如SSO单点登陆。

3:JWT只是消息协议,不牵涉到会话管理和存储机制,所以单体WEB应用还是推荐session-cookie机制。

4、安全策略

1:重放攻击(Replay Attacks):应保证token只能使用一次,可以将有效期设置极短(这个时间不好控制);如果token只使用一次,可以将token的ID放入缓存(redis、memcached)进行阅后即焚(这个可操作性强);如果一个token需要连续穿梭多个系统进行鉴权,在最后一次使用后将token的ID放入销毁缓存(redis、memcached)。

2:跨站请求伪造(CSRF Cross-site request forgery):由于不依赖Cookie,所以一般情况下不需要考虑CSRF。

3:跨站脚本攻击(XSS Cross Site Scripting):相比较CSRF JWT更容易收到XSS的威胁,可以考虑使用过滤器进行处理,JAVA环境下的XSS HTMLFilter和PHP环境下的TWIG。

4:防止伪造令牌:如果使用公私钥密码体系,请注意公钥也应该保密,只对可信系统开放。

二:典型微服务鉴权架构

微服务鉴权架构

客户端(移动端或者pc端)根据口令或者APP KEY到认证服务鉴权并申请签发令牌,如果需要操作服务A,必须先拿着令牌到服务A进行权限问询。如果需要操作服务B,同样先拿着令牌到服务B进行权限问询,一个令牌可以一次,也可以多次使用连续穿梭多个服务系统,直至令牌过期失效或被销毁。

JWT令牌使用了数字签名可以有效的防止数据篡改和窃取,同样申请令牌时的数据也需要有这样的安全保障,可以使用HMAC(哈希运算消息认证码)进行签名(摘要)和验签(参考:基于hmac的rest api鉴权处理)。

shiro是java业界普遍采用的安全框架,简单、够用、扩展性强。我们可以在shiro中添加对HMAC和JWT这两种鉴权方式的支持。

三:shiro集成

1、令牌签发服务

签发服务的核心功能是验证客户端是否合法,如果合法则授予其包含特定访问主张的JWT。

shiro Token定义:

/**
 * HMAC令牌
 * @author wangjie (http://www.jianshu.com/u/ffa3cba4c604) 
 * @date 2016年6月24日 下午2:55:15
 */
public class HmacToken implements AuthenticationToken{
    private static final long serialVersionUID = -7838912794581842158L;
    
    private String clientKey;// 客户标识(可以是用户名、app id等等)
    private String digest;// 消息摘要
    private String timeStamp;// 时间戳
    private Map<String, String[]> parameters;// 访问参数
    private String host;// 客户端IP
    
    public HmacToken(String clientKey,String timeStamp,String digest
                                ,String host,Map<String, String[]> parameters){
        this.clientKey = clientKey;
        this.timeStamp = timeStamp;
        this.digest = digest;
        this.host = host;
        this.parameters = parameters;
    }
    
    @Override
    public Object getPrincipal() {
        return this.clientKey;
    }
    @Override
    public Object getCredentials() {
        return Boolean.TRUE;
    }
    
    // 省略getters and setters ... ...
}
    

shiro Realm即验证逻辑定义:

/**
 * 基于HMAC( 散列消息认证码)的控制域
 * @author wangjie (http://www.jianshu.com/u/ffa3cba4c604) 
 * @date 2016年6月24日 下午2:55:15
 */
public class HmacRealm extends AuthorizingRealm{
    
    private final AccountProvider accountProvider;//账号服务(持久化服务)
    private final CryptogramService cryptogramService;//密码服务

    public HmacRealm(AccountProvider accountProvider,CryptogramService cryptogramService){
        this.accountProvider = accountProvider;
        this.cryptogramService = cryptogramService;
    }
    
    public Class<?> getAuthenticationTokenClass() {
        return HmacToken.class;//此Realm只支持HmacToken
    }
    
    /**
     *  认证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) 
                                                          throws AuthenticationException {
        HmacToken hmacToken = (HmacToken)token;
        List<String> keys = Lists.newArrayList();
        for (String key:hmacToken.getParameters().keySet()){
            if (!"digest".equals(key))
                keys.add(key);
        }
        Collections.sort(keys);//对请求参数进行排序参数->自然顺序
        StringBuffer baseString = new StringBuffer();
        for (String key : keys) {
            baseString.append(hmacToken.getParameters().get(key)[0]);
        }
        //认证端生成摘要
        String serverDigest = cryptogramService.hmacDigest(baseString.toString());
        //客户端请求的摘要和服务端生成的摘要不同
        if(!serverDigest.equals(hmacToken.getDigest())){
            throw new AuthenticationException("数字摘要验证失败!!!");
        }
        Long visitTimeStamp = Long.valueOf(hmacToken.getTimeStamp());
        Long nowTimeStamp = System.currentTimeMillis();
        Long jge = nowTimeStamp - visitTimeStamp;
        if (jge > 600000) {// 十分钟之前的时间戳,这是有效期可以双方约定由参数传过来
            throw new AuthenticationException("数字摘要失效!!!");
        }
        // 此处可以添加查询数据库检查账号是否存在、是否被锁定、是否被禁用等等逻辑
        return new SimpleAuthenticationInfo(hmacToken.getClientKey(),Boolean.TRUE,getName());
    }
    
    /** 
     * 授权 
     */  
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String clientKey = (String)principals.getPrimaryPrincipal();
        SimpleAuthorizationInfo info =  new SimpleAuthorizationInfo();
        // 根据客户标识(可以是用户名、app id等等) 查询并设置角色
        Set<String> roles = accountProvider.loadRoles(clientKey);
        info.setRoles(roles);
      // 根据客户标识(可以是用户名、app id等等) 查询并设置权限
        Set<String> permissions = accountProvider.loadPermissions(clientKey);
        info.setStringPermissions(permissions);
        return info;  
    }
}

HMAC认证过滤器定义:

/**
 * 基于HMAC( 散列消息认证码)的无状态认证过滤器
 * @author wangjie (http://www.jianshu.com/u/ffa3cba4c604) 
 * @date 2016年6月24日 下午2:55:15
 */
public class HmacFilter extends AccessControlFilter{
    
    private static final Logger log = LoggerFactory.getLogger(AccessControlFilter.class);
    
    public static final String DEFAULT_CLIENTKEY_PARAM = "clientKey";
    public static final String DEFAULT_TIMESTAMP_PARAM = "timeStamp";
    public static final String DEFAUL_DIGEST_PARAM = "digest";

    /**
     * 是否放行
     */
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, 
                                                        Object mappedValue) throws Exception {
        if (null != getSubject(request, response) 
                && getSubject(request, response).isAuthenticated()) {
            return true;//已经认证过直接放行
        }
        return false;//转到拒绝访问处理逻辑
    }

    /**
     * 拒绝处理
     */
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response)  
                                                                          throws Exception {
        if(isHmacSubmission(request)){//如果是Hmac鉴权的请求
            //创建令牌
            AuthenticationToken token = createToken(request, response);
            try {
                Subject subject = getSubject(request, response);
                subject.login(token);//认证
                return true;//认证成功,过滤器链继续
            } catch (AuthenticationException e) {//认证失败,发送401状态并附带异常信息
                log.error(e.getMessage(),e);
                WebUtils.toHttp(response).sendError(HttpServletResponse.SC_UNAUTHORIZED,e.getMessage());
            }
        }
        return false;//打住,访问到此为止
    }

    protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) {
        String clientKey = request.getParameter(DEFAULT_CLIENTKEY_PARAM);
        String timeStamp= request.getParameter(DEFAULT_TIMESTAMP_PARAM);
        String digest= request.getParameter(DEFAUL_DIGEST_PARAM);
        Map<String, String[]> parameters = request.getParameterMap();
        String host = request.getRemoteHost();
        return new HmacToken(clientKey, timeStamp, digest, host,parameters);
    }
    
    protected boolean isHmacSubmission(ServletRequest request) {
        String clientKey = request.getParameter(DEFAULT_CLIENTKEY_PARAM);
        String timeStamp= request.getParameter(DEFAULT_TIMESTAMP_PARAM);
        String digest= request.getParameter(DEFAUL_DIGEST_PARAM);
        return (request instanceof HttpServletRequest)
                            && StringUtils.isNotBlank(clientKey)
                            && StringUtils.isNotBlank(timeStamp)
                            && StringUtils.isNotBlank(digest);
    }
}

HMAC鉴权最基础的工作就此完成,需要注意的是鉴权是无状态的不需要创建SESSION,所以需要对shiro的SubjectFactory做一下改造,并设置到SecurityManager :

/**
 * 扩展自DefaultWebSubjectFactory,对于无状态的TOKEN 类型不创建session
 * @author wangjie (http://www.jianshu.com/u/ffa3cba4c604)
 * @date 2016年6月24日 下午2:55:15
 */
public class AgileSubjectFactory extends DefaultWebSubjectFactory { 

    public Subject createSubject(SubjectContext context) { 
        AuthenticationToken token = context.getAuthenticationToken();
        if((token instanceof HmacToken)){
            // 当token为HmacToken时, 不创建 session 
            context.setSessionCreationEnabled(false);
        }
        return super.createSubject(context); 
    }
}

JWT签发逻辑定义:

@RestController
@RequestMapping("/auth")
public class AuthenticateAction {
    private final String SECRET_KEY = "*(-=4eklfasdfarerf41585fdasf";

    @RequestMapping(value="/apply-token",method=RequestMethod.POST)
    public Map<String,Object> applyToken(@RequestParam(name="clientKey") String clientKey) {
        // 签发一个Json Web Token
        // 令牌ID=uuid,用户=clientKey,签发者=clientKey
        // token有效期=1分钟,用户角色=null,用户权限=create,read,update,delete
        String jwt = issueJwt(UUID.randomUUID().toString(), clientKey, 
                                    "token-server",60000l, null, "create,read,update,delete");
        Map<String,Object> respond = Maps.newHashMap();
        respond.put("jwt", jwt);
        return respond;
    }
    
    /**
     * @param id 令牌ID
     * @param subject 用户ID
     * @param issuer 签发人
     * @param period 有效时间(毫秒)
     * @param roles 访问主张-角色
     * @param permissions 访问主张-权限
     * @param algorithm 加密算法
     * @return json web token 
     */
    private String issueJwt(String id,String subject,String issuer,Long period,String roles
                                            ,String permissions,SignatureAlgorithm algorithm) {
        long currentTimeMillis = System.currentTimeMillis();// 当前时间戳
        byte[] secretKeyBytes = DatatypeConverter.parseBase64Binary(SECRET_KEY);// 秘钥
        JwtBuilder jwt  =  Jwts.builder();
        if(Strings.isNotBlank(id)) jwt.setId(id);
        jwt.setSubject(subject);// 用户名主题
        if(Strings.isNotBlank(issuer)) jwt.setIssuer(issuer);//签发者
        if(Strings.isNotBlank(issuer)) jwt.setIssuer(issuer);//签发者  
        jwt.setIssuedAt(new Date(currentTimeMillis));//签发时间
        if(null != period){
            Date expiration = new Date(currentTimeMillis+period);
            jwt.setExpiration(expiration);//有效时间
        }
        if(Strings.isNotBlank(roles)) jwt.claim("roles", roles);//角色
        if(Strings.isNotBlank(permissions)) jwt.claim("perms", permissions);//权限
        jwt.compressWith(CompressionCodecs.DEFLATE);//压缩,可选GZIP
        jwt.signWith(algorithm, secretKeyBytes);//加密设置
        return jwt.compact();
    }
}

添加过滤器:filterChainManager.addFilter( "hmac", new HmacFilter());
配置过滤规则:filterChainManager.addToChain("/auth/**", "hmac");
如果有需要可以在规则中添加其他过滤器。
JWT申请测试:

    @Test
    public String applyToken(){
        Long current = System.currentTimeMillis() ;
        String url = "http://localhost:8080/tokenServer/auth/apply-token";
        MultiValueMap<String, Object> dataMap = new LinkedMultiValueMap<String, Object>();  
        String clientKey = "administrator";// 客户端标识(用户名)
        String mix = String.valueOf(new Random().nextFloat());// 随机数,进行混淆
        String timeStamp = current.toString();// 时间戳
        dataMap.add("clientKey", clientKey);
        dataMap.add("mix", mix);
        dataMap.add("timeStamp", timeStamp);
        String baseString = clientKey+mix+timeStamp;
        String digest =  hmacDigest(baseString);// 生成HMAC摘要
        dataMap.add("digest", digest);
        Map result = rt.postForObject(url, dataMap, Map.class);
        return (String)result.get("jwt");
    }

返回JWT:

eyJhbGciOiJIUzUxMiIsInppcCI6IkRFRiJ9.eNo8y80KwjAQBOB32XMCTfNj7NvsNluI2jYkWxHEdzf14GUYPmbecJMMEwzXGAjnUdvBR-2cdzpSRE2jiUtwSLQEUNAO6mNMa95yk4qy1665ta6y33nTjeuTf4gCk_HGWBvtxSjgV_mDsx0K1_U8zpVRWPVM6ijp7IkfLAyfLwAAAP__.GK7EJibs7n50uGksvvLK6Y39Ur6ZYXoXI9LOlFwEpIijHGAZjIyDhiYD-1nv1YbPJ46BI-gDTntV3KC0d8NSrA

2:令牌验签

有了JWT签发服务,要使用JWT就需要业务系统有JWT验鉴功能,同样在shiro中集成。
由于JWT是自包含的,令牌中已经声明了访问主张(比如角色、权限等),验签功能只需要验证令牌合法就行了,不需要访问数据库。

shiro Token定义:

/**
 * JWT令牌
 * @author wangjie (http://www.jianshu.com/u/ffa3cba4c604) 
 * @date 2016年6月24日 下午2:55:15
 */
public class JwtToken implements AuthenticationToken{

    private static final long serialVersionUID = -790191688300000066L;
    
    private String jwt;// json web token
    private String host;// 客户端IP
    
    public JwtToken(String jwt,String host){
        this.jwt = jwt;
        this.host = host;
    }

    @Override
    public Object getPrincipal() {
        return this.jwt;
    }

    @Override
    public Object getCredentials() {
        return Boolean.TRUE;
    }
    
    // 忽略getters and setters
}
    

JWT Realm即认证逻辑定义:

/**
 * 基于JWT( JSON WEB TOKEN)的认证域
 * 
 * @author wangjie (http://www.jianshu.com/u/ffa3cba4c604)
 * @date 2016年6月24日 下午2:55:15
 */
public class JwtRealm extends AuthorizingRealm {

    public Class<?> getAuthenticationTokenClass() {
        return JwtToken.class;//此Realm只支持JwtToken
    }

    /**
     * 认证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) 
                                                        throws AuthenticationException {
        JwtToken jwtToken = (JwtToken) token;
        String jwt = (String) jwtToken.getPrincipal();
        JwtPlayload jwtPlayload;
        try {
            Claims claims = Jwts.parser()
                    .setSigningKey(DatatypeConverter.parseBase64Binary(SECRETKEY))
                    .parseClaimsJws(jwt)
                    .getBody();
            jwtPlayload = new JwtPlayload();
            jwtPlayload.setId(claims.getId());
            jwtPlayload.setUserId(claims.getSubject());// 用户名
            jwtPlayload.setIssuer(claims.getIssuer());// 签发者
            jwtPlayload.setIssuedAt(claims.getIssuedAt());// 签发时间
            jwtPlayload.setAudience(claims.getAudience());// 接收方
            jwtPlayload.setRoles(claims.get("roles", String.class));// 访问主张-角色
            jwtPlayload.setPerms(claims.get("perms", String.class));// 访问主张-权限
        } catch (ExpiredJwtException e) {
            throw new AuthenticationException("JWT 令牌过期:" + e.getMessage());
        } catch (UnsupportedJwtException e) {
            throw new AuthenticationException("JWT 令牌无效:" + e.getMessage());
        } catch (MalformedJwtException e) {
            throw new AuthenticationException("JWT 令牌格式错误:" + e.getMessage());
        } catch (SignatureException e) {
            throw new AuthenticationException("JWT 令牌签名无效:" + e.getMessage());
        } catch (IllegalArgumentException e) {
            throw new AuthenticationException("JWT 令牌参数异常:" + e.getMessage());
        } catch (Exception e) {
            throw new AuthenticationException("JWT 令牌错误:" + e.getMessage());
        }
        // 如果要使token只能使用一次,此处可以过滤并缓存jwtPlayload.getId()
        // 可以做签发方验证
        // 可以做接收方验证
        return new SimpleAuthenticationInfo(jwtPlayload, Boolean.TRUE, getName());
    }

    /**
     * 授权,JWT已包含访问主张只需要解析其中的主张定义就行了
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        JwtPlayload jwtPlayload = (JwtPlayload) principals.getPrimaryPrincipal();
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        // 解析角色并设置
        Set<String> roles = Sets.newHashSet(StringUtils.split(jwtPlayload.getRoles(), ","));
        info.setRoles(roles);
        // 解析权限并设置
        Set<String> permissions = Sets.newHashSet(StringUtils.split(jwtPlayload.getPerms(), ","));
        info.setStringPermissions(permissions);
        return info;
    }
}

处理逻辑中抛出的异常信息很详细,其实这样并不安全只是对调试友好,线上环境不用把异常信息给那么细。

JWT鉴权过滤器定义:


/**
 * 基于JWT标准的无状态认证过滤器
 * @author wangjie (http://www.jianshu.com/u/ffa3cba4c604) 
 * @date 2016年6月24日 下午2:55:15
 * 
 */ 
public class JwtFilter extends AccessControlFilter {
    
    private static final Logger log = LoggerFactory.getLogger(AccessControlFilter.class);
    
    public static final String DEFAULT_JWT_PARAM = "jwt";

    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
        if (null != getSubject(request, response) 
                && getSubject(request, response).isAuthenticated()) {
            return true;
        }
        return false;
    }

    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        if(isJwtSubmission(request)){
            AuthenticationToken token = createToken(request, response);
            try {
                Subject subject = getSubject(request, response);
                subject.login(token);
                return true;
            } catch (AuthenticationException e) {
                log.error(e.getMessage(),e);
                WebUtils.toHttp(response).sendError(HttpServletResponse.SC_UNAUTHORIZED,e.getMessage());
            } 
        }
        return false;
    }

    protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) {
        String jwt = request.getParameter(DEFAULT_JWT_PARAM);
        String host = request.getRemoteHost();
        log.info("authenticate jwt token:"+jwt);
        System.out.println("jwt:"+jwt);
        return new JwtToken(jwt, host);
    }
    
    protected boolean isJwtSubmission(ServletRequest request) {
        String jwt = request.getParameter(DEFAULT_JWT_PARAM);
        return (request instanceof HttpServletRequest)
                                && StringUtils.isNotBlank(jwt);
    }
    
}

资源访问权限过滤器定义:

/**
 * 基于JWT( JSON WEB TOKEN)的无状态资源过滤器
 * @author wangjie (http://www.jianshu.com/u/ffa3cba4c604) 
 * @date 2016年6月24日 下午2:55:15
 */
public class JwtPermFilter extends HmacFilter{
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, 
                                                    Object mappedValue) throws Exception {
        Subject subject = getSubject(request, response);
        String[] perms = (String[]) mappedValue;
        boolean isPermitted = true;
        if (perms != null && perms.length > 0) {
            if (perms.length == 1) {
                if (!subject.isPermitted(perms[0])) {
                    isPermitted = false;
                }
            } else {
                if (!subject.isPermittedAll(perms)) {
                    isPermitted = false;
                }
            }
        }
        return isPermitted;
    }
    
}

添加过滤器:filterChainManager.addFilter( "jwt", new JwtFilter());
filterChainManager.addFilter( "jwtPerms", new JwtPermFilter());
配置过滤规则:filterChainManager.addToChain("/api/", "jwt");
filterChainManager.addToChain("/api/delete/
", "jwtPerms["api:delete"]");
如果有需要可以在规则中添加其他过滤器。
同令牌申请服务一样,需要设置shiro不创建SESSION。

 

 

jsets-shiro-spring-boot-starter中封装了JWT的鉴权,请参见:

项目文档、源码

项目中经常用到的功能比如:验证码、密码错误次数限制、账号唯一用户登陆、动态URL过滤规则、无状态鉴权等等jsets-shiro-spring-boot-starter对这些常用的功能进行了封装和自动导入,少量的配置就可以应用在项目中。

1、jsets-shiro-spring-boot-starter项目详情请参见:jsets-shiro-spring-boot-starter
2、应用示例源码请参见:jsets-shiro-demo
3、jsets-shiro-spring-boot-starter使用说明请参见:使用说明

分享到:
评论
1 楼 ioandy 2019-05-21  
博主,无状态时jwt, 登录后每次请求在isAccessAllowed方法中subject.isAuthenticated() 还是false,请教下这是什么问题?

相关推荐

    基于SpringBoot、Mybaitis-Plus、Redis、Shiro+JWT构建无状态、Hadoop的云网盘存储系统

    【标题】基于SpringBoot、Mybatis-Plus、Redis、Shiro+JWT构建的无状态、Hadoop云网盘存储系统,旨在实现一个高效、安全、可扩展的分布式存储解决方案。这个项目融合了现代Web开发技术和大数据处理框架,为用户提供...

    Shiro + JWT + SpringBoot + MySQL + Redis(Jedis)实现无状态鉴权机制

    在现代Web应用中,无状态鉴权机制是重要的安全实践,它可以提高系统的可扩展性和性能。本项目结合了Apache Shiro、JSON Web Token (JWT)、SpringBoot、MySQL数据库以及Redis缓存技术(通过Jedis客户端)来实现这一...

    Shiro + Java-JWT无状态鉴权认证机制

    《Shiro + Java-JWT无状态鉴权认证机制在SpringBoot环境中的应用》 在现代Web应用程序中,安全性和权限管理是至关重要的组成部分。本文将深入探讨如何在SpringBoot项目中结合Apache Shiro和Java JSON Web Tokens ...

    SpringBoot集成Shiro、Jwt和Redis

    通过以上步骤,我们可以构建一个完整的RBAC系统,其中Shiro处理权限控制,Jwt实现无状态认证,Redis提供高效的会话管理,而MyBatisPlus则简化了数据库操作。这样的系统不仅安全可靠,而且具有良好的扩展性和可维护性...

    基于springboot+shiro+jwt+vue+redis的后台管理系统源码.zip

    1、基于springboot+shiro+jwt+vue+redis的后台管理系统源码.zip 2、该资源包括项目的全部源码,下载可以直接使用! 3、本项目适合作为计算机、数学、电子信息等专业的课程设计、期末大作业和毕设项目,作为参考资料...

    shiro jwt登录认证

    该项目使用了springboot、mybaits-plus、jwt、shiro、redis。mybaits-plus基本没用,只做了一次数据库查询,redis暂时不使用,登录验证成功后再追加redis操作。

    febs_shiro_jwt-master_java_;shiro;jwt_

    JWT则是一种用于身份验证的开放标准,可以生成和验证用户身份令牌,使得在分布式系统中实现无状态的认证。 **SpringBoot知识点:** 1. 自动配置:SpringBoot通过“@EnableAutoConfiguration”注解自动配置应用,...

    基于SpringBoot、Mybaitis-Plus、Redis、Shiro+JWT构建无状态、的云网盘存储系统+源代码+文档说

    | Shiro | 认证和授权框架 | [http://shiro.apache.org/](http://shiro.apache.org/) | | MyBatis-Plus | ORM框架 | [https://mp.baomidou.com/l](https://mp.baomidou.com/l) | | PageHelper | MyBatis物理分页插件...

    SpringBoot+Shiro+JWT+Jedis+MybatisPlus+前后端分离+基于url通用权限管理系统

    总的来说,这个系统通过SpringBoot构建基础框架,利用Shiro进行权限控制,结合JWT实现无状态认证,借助Jedis提升性能,运用MybatisPlus简化数据库操作,实现了基于URL的权限管理。这种设计不仅提高了系统的安全性,...

    shiro基于RBAC模型的分布式权限管理系统教程及源码

    18章完整的基于shiro的分布式权限管理系统,包含完整的教程及源码,学过此教程,觉得很有意义,特意来分享。

    sping-boot-shiro-jwt-redis.zip

    而Shiro和JWT则是常见的身份验证和授权工具,它们能够帮助我们构建安全的权限管理系统。此外,Redis作为高性能的内存数据存储,常被用于缓存,以提升系统性能。本篇文章将深入探讨如何在Spring Boot项目中整合Shiro...

    springboot shiro pac4j cas jwt认证中心sso完整项目

    本项目基于SpringBoot框架,结合Shiro、pac4j和CAS,构建了一个完整的JWT认证中心,旨在实现高效、安全的SSO解决方案。 1. **SpringBoot**: SpringBoot是Spring框架的一个扩展,它简化了Spring应用的初始搭建以及...

    基于 Shiro 与JWT 的Spring Boot无状态鉴权教程及项目.zip

    1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,...

    springboot整和jwt、shiro、redis实现token自动刷新

    结合JWT(JSON Web Token)和Shiro,我们可以构建一个高效的身份验证和授权系统,同时利用Redis缓存来提高性能和用户体验。下面将详细介绍如何在Spring Boot中整合JWT、Shiro和Redis实现Token自动刷新。 JWT是一种...

    SpringBoot+shiro+redis+jwt .zip

    `JWT`的引入是为了实现无状态的身份验证。用户登录成功后,服务器会生成一个包含用户信息的JWT,并返回给客户端。之后,客户端在每次发送请求时,都将这个JWT放在`Authorization`头中。服务器端验证JWT的有效性,...

    基于Spring MVC+MyBatis+Shiro+Dubbo开发的分布式后台管理系统(含数据库文件).zip

    总结来说,这个系统结合了Spring MVC的Web开发能力,MyBatis的数据操作便利性,Shiro的安全管理,以及Dubbo的分布式服务治理,构建了一个完整的分布式后台管理系统,能够应对高并发、大规模数据处理的需求。...

    java的实现权限控制shiro jwt.docx

    总的来说,Java的权限控制结合Shiro和JWT可以创建一个安全的、无状态的身份验证系统,有效地管理用户的访问权限,并允许在分布式环境中轻松地扩展。同时,通过自定义过滤器和Realm,可以根据实际需求定制化的实现...

    springboot集成jwt和shiro实现前后端分离权限demo2

    而JWT(JSON Web Token)和Shiro是两个常用于权限管理的工具,它们能够帮助我们构建安全的、基于令牌的身份验证系统。本文将详细介绍如何在Spring Boot项目中集成JWT和Shiro,以及如何处理Realm中的异常。 首先,...

    基于shiro前后端分离分布式权限管理(完整后端代码)

    在IT行业中,权限管理是构建安全系统的关键环节。本文将深入探讨基于Apache Shiro实现的前后端分离的分布式权限管理系统,结合Redis集群进行缓存管理的详细知识点。 首先,Apache Shiro是一个强大且易用的Java安全...

    管理系统系列--基于Spring MVC+MyBatis+Shiro+Dubbo开发的分布式后台管理系统.zip

    本系统采用了业界广泛使用的四大核心技术——Spring MVC、MyBatis、Shiro和Dubbo,构建了一个强大的分布式后台管理框架。下面将对这四大技术进行详细阐述,并探讨它们如何协同工作,以实现高效、安全的后台管理。 ...

Global site tag (gtag.js) - Google Analytics