文章目录

  • token类
  • 自定义realm
  • 自定义的jwtFilter用于访问拦截:
  • shiroconfig
  • controller
  • vo对象
  • 测试

jwt和shiro框架就不多介绍了,直接上实例代码吧。目前测试可正常登录、获得用户角色、访问接口时根据@requireRoles进行拦截。

token类


import org.apache.shiro.authc.AuthenticationToken;
//一般的登陆只需要校验账号和密码两个要素,默认的UsernamePasswordToken就能满足需求
//这个就类似UsernamePasswordToken
//在JwtRealm中的授权部分,可以使用JwtUtil.decode(jwt).get("username")获取到username,使用username去数据库中查找到对应的权限,然后将权限赋值给这个用户就可以实现权限的认证了public class JWTToken implements AuthenticationToken {private String token;public JWTToken(String token){this.token = token;}@Overridepublic Object getPrincipal() {return token;}@Overridepublic Object getCredentials() {return token;}
}

自定义realm

@Slf4j
public class JwtRealm extends AuthorizingRealm {/** 多重写一个support* 标识这个Realm是专门用来验证JwtToken* 不负责验证其他的token(UsernamePasswordToken)* */@Overridepublic boolean supports(AuthenticationToken token) {//这个token就是从过滤器中传入的jwtTokenreturn token instanceof JWTToken;}@Autowiredprivate IInowRoleUserService roleUserService;@Autowiredprivate IInowRoleService roleService;@Autowiredprivate IInowUserService userService;//授权@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {log.info("=========执行了授权===========================");InowUser userName = (InowUser) principalCollection.getPrimaryPrincipal();InowUser inowUser = userService.selectOneByName(userName.getUserName());SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();final InowRoleUser roleuser = roleUserService.getOne(new LambdaQueryWrapper<InowRoleUser>().eq(InowRoleUser::getUserId, inowUser.getUserId()));List<String> inowRoleList = new ArrayList<>();inowRoleList.add(roleService.getOne(new LambdaQueryWrapper<InowRole>().eq(InowRole::getId,roleuser.getRoleId())).getRoleName());simpleAuthorizationInfo.addRoles(inowRoleList);//添加用户角色,用于@requireroles注解return simpleAuthorizationInfo;}//认证// 这里的 token是从 JWTFilter 的 executeLogin 方法传递过来的(请求头的token)// 只要调用了subject.login(token)方法,就会进入到realm的doGetAuthenticationInfo内。@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) throws AuthenticationException {String token = (String)auth.getCredentials();log.info("从auth获得的Token"+token);String userName = JWTUtil.getUsername(token);//用户不存在(这个在登录时不会进入,只有在token校验时才有可能进入)if(userName == null){throw new UnknownAccountException();}InowUser user = userService.selectOneByName(userName);if(Objects.isNull(user)){throw new UnknownAccountException();}String salt = "666666"; //自己随便写的一个加密盐Md5Hash md5Hash = new Md5Hash(user.getUserId(), salt, 1024);
if(!JWTUtil.verify(token,userName, md5Hash.toHex()))//学号当做用户密码{throw new IncorrectCredentialsException();}//toke过期if(JWTUtil.isExpire(token)){throw new ExpiredCredentialsException();}return new SimpleAuthenticationInfo(user, token, getName());}}

自定义的jwtFilter用于访问拦截:

@Slf4j
//@Component("jwtFilter")
//去掉@Component注解,让filter不交给springbean管理,因为这会导致shiro内置的anon过滤器失效,具体原因还未找出
public class JwtFilter extends BasicHttpAuthenticationFilter {/*** 进行token的验证*/@Overrideprotected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {//在请求头中获取tokenHttpServletRequest httpServletRequest = (HttpServletRequest) request;String token = httpServletRequest.getHeader("Authorization"); //前端命名Authorization//token不存在if(token == null || "".equals(token)){Result result = new Result();result.setCode(400);result.setMsg("token为空,无法访问");out(response,result);return false;}//token存在,进行验证JWTToken jwtToken = new JWTToken(token);try {SecurityUtils.getSubject().login(jwtToken);  //通过subject,提交给myRealm进行登录验证return true;} catch (ExpiredCredentialsException e){Result result = new Result();result.setCode(400);result.setMsg("登录已经过期");
out(response,result);e.printStackTrace();return false;} catch (ShiroException e){// 其他情况抛出的异常统一处理,由于先前是登录进去的了,所以都可以看成是token被伪造造成的Result res = new Result();res.setMsg("无效token");out(response,res);e.printStackTrace();return false;}}/*** json形式返回结果token验证失败信息,无需转发*/private void out(ServletResponse response, Result res) throws IOException {HttpServletResponse httpServletResponse = WebUtils.toHttp(response);ObjectMapper mapper = new ObjectMapper();String jsonRes = mapper.writeValueAsString(res);httpServletResponse.setCharacterEncoding("UTF-8");httpServletResponse.setContentType("application/json; charset=utf-8");httpServletResponse.getOutputStream().write(jsonRes.getBytes());}/*** 过滤器拦截请求的入口方法*/@Overrideprotected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {try {return executeLogin(request, response);  //token验证} catch (Exception e) {e.printStackTrace();return false;}}/*** isAccessAllowed()方法返回false,即认证不通过时进入onAccessDenied方法*/
//    @Override
//    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {//        return super.onAccessDenied(request, response);
//    }/*** token认证executeLogin成功后,进入此方法,可以进行token更新过期时间*/
//    @Override
//    protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception {//    }
}

shiroconfig


@Configuration
public class ShiroConfig {public logOutFilter mylogoutFilter(){logOutFilter MylogoutFilter = new logOutFilter();MylogoutFilter.setLoginUrl("login");//设置退出后重定向的跳转地址return MylogoutFilter;}/*** 注入Shiro过滤器链配置* 注入安全服务配置* 注入自定义jwt过滤器**/@Beanpublic ShiroFilterFactoryBean shiroFilterFactoryBean(@Autowired @Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager,@Autowired ShiroFilterChainDefinition definition){JwtFilter jwtFilter = new JwtFilter();ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();bean.setSecurityManager(defaultWebSecurityManager);//设置安全管理器//可以添加shiro的内置过滤器//anon:无需认证就可以访问 authc:必须认证了才能用 oerms:拥有对某个资源的权限才能访问bean.setLoginUrl("/login");//设置登录路径//bean.setUnauthorizedUrl("/unlogin");Map<String, Filter> filterMap = new HashMap<>();// 注销成功,则跳转到指定页面filterMap.put("logout", mylogoutFilter());filterMap.put("anon", new AnonymousFilter());filterMap.put("jwt",jwtFilter);
bean.setFilters(filterMap);bean.setFilterChainDefinitionMap(definition.getFilterChainMap());return bean;}/*** 自定义jwt过滤器** @return*///@Beanpublic JwtFilter jwtFilter(){return new JwtFilter();}/*** 定义拦截器链,所有请求都经过自定义的jwt过滤器** @return*/@Beanpublic ShiroFilterChainDefinition shiroFilterChainDefinition(){DefaultShiroFilterChainDefinition definition = new DefaultShiroFilterChainDefinition();Map<String,String> map = new LinkedHashMap<>();map.put("/login","anon");map.put("/swagger-ui.html","anon");map.put("/doc.html","anon");map.put("/**","jwt");definition.addPathDefinitions(map);return definition;}/*** 自定义Realm** @return*/@Beanpublic JwtRealm myUserRealm(){JwtRealm userRealm = new JwtRealm();return userRealm;}/*** 开启认证授权注解** @param securityManager* @return*/@Beanpublic AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Autowired DefaultWebSecurityManager securityManager){AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);return authorizationAttributeSourceAdvisor;}@Beanpublic LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {return new LifecycleBeanPostProcessor();}@Bean@DependsOn("lifecycleBeanPostProcessor")//DefaultAdvisorAutoProxyCreator://BeanPostProcessor实现,它根据当前BeanFactory中的所有候选Advisor创建 AOP 代理。public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();// 强制指定注解的底层实现使用 cglib 方案,防止重复代理和可能引起代理出错的问题defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);return defaultAdvisorAutoProxyCreator;}/*** 配置安全服务机制,注入自定义Realm,关闭了shiro的默认session机制** @param* @return*//** 关闭shiro自带的session,详情见文档* http://shiro.apache.org/session-management.html#SessionManagement-StatelessApplications%28Sessionless%29*//** a. 告诉shiro不要使用默认的DefaultSubject创建对象,因为不能创建Session* */@Beanpublic SubjectFactory subjectFactory() {return new JwtDefaultSubjectFactory();}@Bean("securityManager")public DefaultWebSecurityManager securityManager(@Autowired JwtRealm myRealm) {DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();securityManager.setRealm(myRealm);// 关闭 ShiroDAO 功能DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();// 不需要将 Shiro Session 中的东西存到任何地方(包括 Http Session 中)defaultSessionStorageEvaluator.setSessionStorageEnabled(false);subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);securityManager.setSubjectDAO(subjectDAO);//禁止Subject的getSession方法securityManager.setSubjectFactory(subjectFactory());return securityManager;}}

controller

  @ApiOperation("登录接口")@GetMappingpublic Result userLogin(@ApiParam(name="userId",value="用户学号",required=true)@RequestParam(value = "userId",required = true)String userId,@ApiParam(name="userName",value="用户姓名",required=true)@RequestParam(value = "userName",required = true)String userName) {// 1、获取Subject实例对象//根据用户名获取正确用户信息InowUser user = userService.selectOneByName(userName);if(user == null){return Result.fail("无效用户,请检查您的姓名");}//盐 + 输入的密码(注意不是用户的正确密码) + 1024次散列,作为token生成的密钥String salt = "666666";Md5Hash md5Hash = new Md5Hash(userId, salt, 1024);//生成token字符串String token = JWTUtil.getJwtToken(userName, md5Hash.toHex());   //toHex转换成16进制,32为字符log.info("从controller生成的Token"+token);JWTToken jwtToken = new JWTToken(token);Subject currentUser = SecurityUtils.getSubject();// 4、认证try {currentUser.login(jwtToken);// 传到Realm类中的方法进行认证 进入 AuthenticationInfo方法//session.setAttribute("username", userName);InowUser nowUser = (InowUser) currentUser.getPrincipal();InowUserVo userVo = new InowUserVo();BeanUtils.copyProperties(nowUser,userVo);userVo.setToken(token);return Result.success(userVo);}catch (AuthenticationException e) {String msg = null;if (StringUtils.isNotEmpty(e.getMessage())) {msg = e.getMessage();}return Result.fail("用户名与学号不匹配!");}//   }}

vo对象

在vo中放了token属性的成员属性

@Data
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class InowUserVo implements Serializable {private static final long serialVersionUID = 1L;/** 学号或者教师id */@NotBlank(message = "id不能为空!")@ApiModelProperty(value="用户id,学号或教师号",name="id",example="2020214283")private String userId;private Integer id;/** 姓名 */@NotBlank(message = "姓名不能为空!")@ApiModelProperty(value="用户姓名",name="userName",example="张三")private String userName;/** 学院 */@ApiModelProperty(value="用户学院",name="userAcademy",example="计算机与信息学院")private String userAcademy;/** 微信id */@ApiModelProperty(value="微信id",name="wechatId",example="微信id")private Long wechatId;@ApiModelProperty(value="性别",name="userSex",example="1男,2女")private byte userSex;@ApiModelProperty(value="最后登陆时间",name="loginDate")private Date loginDate;@ApiModelProperty(value="用户角色",name="roleName")private String roleName;
private String token;
}

测试

登录接口:

访问一个标有注解@RequireRoles(“admin”)的方法:
在不加token时返回结果:

加一个没有Admin角色的Token访问结果:

用有admin角色的用户token访问结果:

shiro+jwt进行认证和授权的解决方案代码实例相关推荐

  1. 服务架构:统一身份认证和授权技术解决方案

    本文讨论的是基于微服务架构下的身份认证和用户授权的技术方案,从背景到微服务架构整套流程分解. 一.预备知识 本文讨论基于微服务架构下的身份认证和用户授权的技术方案,在阅读之前,最好先熟悉并理解以下几个 ...

  2. 5.1基于JWT的认证和授权「深入浅出ASP.NET Core系列」

    原文:5.1基于JWT的认证和授权「深入浅出ASP.NET Core系列」 希望给你3-5分钟的碎片化学习,可能是坐地铁.等公交,积少成多,水滴石穿,码字辛苦,如果你吃了蛋觉得味道不错,希望点个赞,谢 ...

  3. shiro+jwt登录认证anon配置无效

    shiro+jwt登录认证anon配置无效 需求:使用shiro+jwt进行登录认证,希望可以自定义一些不需要认证的接口(登录接口等),其他统统交给jwtFilter进行token认证 原来shiro ...

  4. GitHub开源项目学习 电商系统Mall (五) mall整合SpringSecurity和JWT实现认证和授权(二)

    mall整合SpringSecurity和JWT实现认证和授权(二) https://github.com/macrozheng/mall 登录注册功能实现 UmsAdminController类 实 ...

  5. GitHub开源项目学习 电商系统Mall (四) mall整合SpringSecurity和JWT实现认证和授权(一)

    mall整合SpringSecurity和JWT实现认证和授权(一) https://github.com/macrozheng/mall 跳过了官方Learning中较简单的Swagger-UI的实 ...

  6. 商城项目(三)整合SpringSecurity和JWT实现认证和授权

    整合SpringSecurity和JWT实现认证和授权 环境搭建 SpringSecurity JWT Hutool 项目使用表说明 ums_admin:后台用户表 ums_role:后台用户角色表 ...

  7. SpringBoot+SpringSecurity+JWT实现认证和授权

    SprinBoot 系列文章: Spring Boot入门之Hello Spring Boot SpringBoot 配置多个JdbcTemplate SpringBoot 整合Mybatis CAS ...

  8. ASP.NET Core WebAPI中使用JWT Bearer认证和授权

    为什么是 JWT Bearer ASP.NET Core 在 Microsoft.AspNetCore.Authentication 下实现了一系列认证, 包含 Cookie, JwtBearer,  ...

  9. SpringBoot整合Shiro实现登录认证和授权CHCache

    文章目录 一. springboot实现普通登录 1 添加依赖 2 编写配置文件 3 新建实体类和mapper 4 编写业务层代码 5 编写控制器 6 编写启动类 7 编写登录页面和主页面 二. sp ...

最新文章

  1. 将本地工程上传到github
  2. Matlab中plot函数及legend函数详解
  3. java字符转为数字_Java 判断字符串能否转化为数字的三种方法
  4. 远程连接电脑_Python黑科技:在家远程遥控公司电脑,python+微信一键连接!
  5. 杭电4561 连续最大积
  6. python怎么保存为nii文件_Ubuntu+python将nii图像保存成png格式
  7. 公链史记 | 从鸿蒙初辟到万物生长的十年激荡
  8. 2022年各种经典java小游戏
  9. 电力系统同步发电机励磁系统的建模与仿真
  10. 【JXTA概念介绍(翻译)】
  11. java实现pdf预览和下载
  12. 代做matlab程序价格,代做data collection、Matlab设计代写、Matlab代做、代做Matlab编程代写R语言程序|代做R语言编程...
  13. Python3 - Dockerfile 最佳实践
  14. Java学习笔记(13)-构造方法
  15. 数据库系统概念 - 数据模型,关系模型,关系,候选码,主码,外码
  16. 基于ng-alain做国际化
  17. 计算机软件专利申请研究
  18. 2.CreateWindowEx
  19. 虚拟逃避现实非常适合大流行,但虚拟现实似乎离主流技术还很远
  20. 机器学习 李宏毅 L24-Linear Dimension Reduction

热门文章

  1. linux 搭建.net运行环境,.net core运行环境搭建 linux + windows
  2. python如何初始化一个二维数组_使用Python实现一个简单的商品期货布林指标突破策略...
  3. java为什么要初始化_JAVA中到底要怎么样初始化
  4. collection集合 多少钱_Java 集合(2)-- Iterator接口源码超级详细解析
  5. java的imshow方法_如何在循环中使用子图,imshow或图形来显示所有图像?
  6. location驱动包_Zynq SDK 驱动探求(三):论一个外设驱动的全部身家·Xilinx SDK 驱动源码结构...
  7. 九十六、轻松搞定Python中的PPT办公自动化系列
  8. libsvm matlab 调参数,matlab – 使用libsvm调整svm
  9. ICLR 2022 | Transformer不比CNN强!Local Attention和动态Depth-wise卷积
  10. 梯度下降(Gradient Descent)的收敛性分析