shiro的原理已经有博客了,自己写可以问度娘
参考https://www.cnblogs.com/liyinfeng/p/8033869.html
此处直接描述实际使用
一、pom.xml引包
<!--shiro--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.3.2</version> </dependency>
二、三件套
ShiroConfig
@Configuration public class ShiroConfig { @Bean public ShiroFilterFactoryBean shirFilter(DefaultWebSecurityManager securityManager) { System.out.println("ShiroConfiguration.shirFilter()"); ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); //拦截器. Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>(); // 配置不会被拦截的链接 顺序判断 /**静态文件css及图片*/ filterChainDefinitionMap.put("/static/**", "anon"); /**webservice服务*/ filterChainDefinitionMap.put("/services/**", "anon"); filterChainDefinitionMap.put("/token/**", "anon"); filterChainDefinitionMap.put("/swagger-ui.html", "anon"); filterChainDefinitionMap.put("/webjars/**", "anon"); filterChainDefinitionMap.put("/v2/**", "anon"); filterChainDefinitionMap.put("/swagger-resources/**", "anon"); //配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了 filterChainDefinitionMap.put("/logout", "logout"); //<!-- 过滤链定义,从上向下顺序执行,一般将/**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了; //<!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问--> filterChainDefinitionMap.put("/**", "authc"); // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面 shiroFilterFactoryBean.setLoginUrl("/login"); // 登录成功后要跳转的链接 shiroFilterFactoryBean.setSuccessUrl("/index"); //未授权界面; shiroFilterFactoryBean.setUnauthorizedUrl("/403"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } @Bean public MyShiroRealm myShiroRealm(){ MyShiroRealm myShiroRealm = new MyShiroRealm(); return myShiroRealm; } @Bean public DefaultWebSecurityManager securityManager(){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(myShiroRealm()); return securityManager; } }
MyShiroRealm
@Slf4j public class MyShiroRealm extends AuthorizingRealm { @Autowired private UserInfoService userInfoService; /***授权方法*/ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) { log.info("开始授权 --> MyShiroRealm.doGetAuthorizationInfo()"); SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); UserInfo userInfo = (UserInfo)principal.getPrimaryPrincipal(); for(SysRole role:userInfo.getRoleList()){ authorizationInfo.addRole(role.getRole()); for(SysPermission p:role.getPermissions()){ authorizationInfo.addStringPermission(p.getPermission()); } } log.info("结束成功!"); return authorizationInfo; } /**认证方法*/ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { log.info("开始认证 --> MyShiroRealm.doGetAuthenticationInfo()"); //获取用户的输入的账号. String username = (String)token.getPrincipal(); System.out.println(token.getCredentials()); //通过username从数据库中查找 User对象,如果找到,没找到. //实际项目中,这里可以根据实际情况做缓存,如果不做,Shiro自己也是有时间间隔机制,2分钟内不会重复执行该方法 log.info("认证 --> 通过账户查询入参"+username); UserInfo userInfo = userInfoService.findByUsername(username); log.info("认证 --> 通过账户查询出参"+ JSON.toJSONString(userInfo)); if(userInfo == null){ log.info("认证失败!"); return null; } SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo( userInfo, //用户名 userInfo.getPassword(), //密码 ByteSource.Util.bytes(userInfo.getSalt()),//salt=username+salt getName() //realm name ); log.info("认证成功!"); return authenticationInfo; } }
给shiro添加token,这时token中的用户才会执行认证授权的流程
@ApiOperation("登陆获取token") @PostMapping("/login") @LoginToken public Object login(@RequestParam("username") String username, @RequestParam("password") String password) { JSONObject jsonObject = new JSONObject(); UserInfo userInfo = userInfoService.findByUsername(username); if (userInfo == null) { jsonObject.put("message", "登录失败,用户不存在"); return jsonObject; } else { EncryptUtil encryptUtil = EncryptUtil.getInstance(); String passcode = encryptUtil.MD5(encryptUtil.Base64Encode(password) + userInfo.getSalt()); //校验登陆密码加盐的一致性 if (!userInfo.getPassword().equals(passcode)) { jsonObject.put("message", "登录失败,密码错误"); return jsonObject; } else { //shiro的token //添加用户认证信息 Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken shiroToken = new UsernamePasswordToken(userInfo.getUsername(),userInfo.getPassword()); //进行验证,这里可以捕获异常,然后返回对应信息 subject.login(shiroToken); SignInReq sign = new SignInReq(); sign.setId(Integer.toString(userInfo.getUid())); sign.setUserName(userInfo.getUsername()); //此处的密码是加盐加密过后的 sign.setPassword(userInfo.getPassword()); long now = System.currentTimeMillis(); String dateStr = DateUtil.parseDateToStr(new Date(now+expireTime), DateUtil.DATE_TIME_FORMAT_YYYY_MM_DD_HH_MI_SS); String token = JwtTokenUtil.createJWT(expireTime, sign); jsonObject.put("token", token); jsonObject.put("expireTime",dateStr); jsonObject.put("sign", sign); return jsonObject; } } }
当然权限crud的自己来一套
最后就可以用了,哈哈