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

网友投稿 444 2022-12-19


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

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

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

先下载shiro和jwt的jar包

org.apache.shiro

shiro-spring

1.4.0

org.apache.shiro

shiro-ehcache

1.4.0

com.auth0

java-jwt

3.4.0

io.jsonwebtoken

jjwt

0.9.0

创建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 roleModels = loginService.selectRoleDetails(user.getId());

try {

/**

* 创建一个Set,来放置用户拥有的权限

* 创建 SimpleAuthorizationInfo, 并将办好权限列表的Set放入.

*/

Set rolesSet = new HashSet();

for (String role : roleModels) {

rolesSet.add(role);

}

info = new SimpleAuthorizationInfo();

info.setStringPermissions(rolesSet); // 放入权限信息

}catch (Exception e){

throw new AuthenticationException("授权失败!");

}

return info;

}

}

这个授权方法遇到的坑比较少,就是在最终验证的时候网上很照抄过来的帖子一点都没有验证就粘贴赋值,在这里严重吐槽。

在使用jwt最为token而取消shiro传统的session时候,我们的需要重写shiro的验证接口   CredentialsMatcher,在 自定义的realm

中我们加入我们重写的验证方法,在调用SimpleAuthenticationInfo()方法进行验证的时候,shiro就会使用重写的验证接口。

此处为大坑。

贴上代码如下:

import com.spring.common.auto.autoUser.extend.AutoModelExtend;

import org.apache.log4j.Logger;

import org.apache.shiro.authc.AuthenticationInfo;

import org.apache.shiro.authc.AuthenticationToken;

import org.apache.shiro.authc.credential.CredentialsMatcher;

/**

* CredentialsMatcher

* 接口由类实现,该类可以确定是否提供了AuthenticationToken凭证与系统中存储的相应帐户的凭证相匹配。

* Shiro 加密匹配 重写匹配方法CredentialsMatcher 使用JWTUtil 匹配方式

*/

public class JWTCredentialsMatcher implements CredentialsMatcher {

private Logger logger = Logger.getLogger(JWTCredentialsMatcher.class);

/**

* Matcher中直接调用工具包中的verify方法即可

*/

@Override

public boolean doCredentialsMatch(AuthenticationToken authenticationToken, AuthenticationInfo authenticationInfo) {

String token = (String) ((JwtToken)authenticationToken).getToken();

AutoModelExtend user = (AutoModelExtend)authenticationInfo.getPrincipals().getPrimaryPrincipal();

//得到DefaultJwtParser

Boolean verify = JwtUtil.isVerify(token, user);

logger.info("JWT密码效验结果="+verify);

return verify;

}

}

shiro的配置项  ShiroConfiguration代码如下:

import com.serverprovider.config.shiro.shiroSysFile.JwtFilter;

import com.serverprovider.config.shiro.userRealm.UserRealm;

import org.apache.log4j.Logger;

import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;

import org.apache.shiro.mgt.DefaultSubjectDAO;

import org.apache.shiro.mgt.SecurityManager;

import org.apache.shiro.mgt.SessionStorageEvaluator;

import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;

import org.apache.shiro.spring.web.ShiroFilterFactoryBean;

import org.apache.shiro.web.mgt.DefaultWebSecurityManager;

import org.apache.shiro.web.mgt.DefaultWebSessionStorageEvaluator;

import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;

import java.util.*;

@Configuration

public class ShiroConfiguration {

private Logger logger = Logger.getLogger(ShiroConfiguration.class);

@Bean("shiroFilter")

public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {

ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();

shiroFilterFactoryBean.setSecurityManager(securityManager);

//拦截器

Map filterChainDefinitionMap = new LinkedHashMap();

// 配置不会被拦截的链接 顺序判断

filterChainDefinitionMap.put("/login/**", "anon");

// 添加自己的过滤器并且取名为jwt

Map filterMap = new HashMap();

filterMap.put("jwt", new JwtFilter());

shiroFilterFactoryBean.setFilters(filterMap);

//


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Shiro+Cas微服务化及前后端完全分离
下一篇:java判断字符串包含某个字符的实例方法
相关文章

 发表评论

暂时没有评论,来抢沙发吧~