shiro使用(最终集成springboot代码合集)

至此,shiro和springboot和JWT的集成全部完毕,下面为完整代码。

第一:shiroConfig,整个shiro的配置类。

这里sesssion交给了shiro默认去管理,不在做过多的配置,一方面shiro的session时间够用了,另一方便,没必要把配置类搞得这么庞大,以前的shiro文章里特地讲了shiro的session,包括集成quatz。请看这里


/**
 * shiro配置类
 */
@Configuration
public class ShiroConfig {

    @Bean("rememberCookie")
    public SimpleCookie rememberCookie(){
        SimpleCookie simpleCookie = new SimpleCookie();
        simpleCookie.setHttpOnly(true);
        simpleCookie.setName("remeberCookie");
        simpleCookie.setMaxAge(360000);
        return simpleCookie;
    }
    @Bean("cookieRememberMe")
    public CookieRememberMeManager cookieRememberMe(){
        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
        cookieRememberMeManager.setCookie(rememberCookie());
        return cookieRememberMeManager;
    }

    /**
     * 密码加密
     * @return
     */
    @Bean("credentialsMatcher")
    public HashedCredentialsMatcher credentialsMatcher(){
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName("SHA-256");
        hashedCredentialsMatcher.setHashIterations(20);
        hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);
        return hashedCredentialsMatcher;
    }
    @Bean("shiroRealm")
    public ShiroRealm shiroRealm(){
        ShiroRealm shiroRealm = new ShiroRealm();
        shiroRealm.setCredentialsMatcher(credentialsMatcher());
        return shiroRealm;
    }

    /**
     * 这里session交给shiro默认管理,不去做详细配置
     * @return
     */
    @Bean("securityManager")
    public SecurityManager securityManager(){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //传入自定义shiroRealm
        securityManager.setRealm(shiroRealm());
        //这里要注意,setRememberMeManager里传入的类型是CookieRememberMeManager,不要搞错了
        securityManager.setRememberMeManager(cookieRememberMe());
        return securityManager;
    }

    /**
     * 这里不设置loginUrl,传统的前后端不分离是可以配置,
     * 因为这里前后端分离,前端没有获取到token自然会路由到登录页面进行登录操作,不再需要通过loginUrl定位到视图view,SpringBoot只负责后端
     * 同时注意这里的filterMap中对于拦截路径的配置要以 / 开头,否则找不到对应的Controller,
     * 切记:一定要把/** = authc放到最后!!!!!
     * 2019-05-12补充说明:对于loginUrl最终还是需要的,filter里会进行是否为登录url的判断。
     * @param securityManager
     * @return
     */
    @Bean("shiroFilter")
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager,AuthFilter authFilter){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        shiroFilterFactoryBean.setLoginUrl("/user/login");
        //设置自定义filter
        Map<String, Filter> filter = new HashMap<>();
        filter.put("auth",authFilter);
        shiroFilterFactoryBean.setFilters(filter);
        //同时这里注意,使用LinkedHashMap来保证拦截器的顺序性
        Map<String,String> filterMap = new LinkedHashMap<>();
        //登录逻辑这里不用anno,统一走自定义filter
        //filterMap.put("/user/login","anon");
        filterMap.put("/user/insert","auth");
        filterMap.put("/**","auth");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
        return shiroFilterFactoryBean;
    }

    /**
     * Spring管理Shiro生命周期
     * @return
     */
    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){
        return new LifecycleBeanPostProcessor();
    }
}

第二:shiroRealm,承担着shiro的认证和授权工作。

/**
 * 自定义shiroRealm
 */
public class ShiroRealm extends AuthorizingRealm {
    @Autowired
    UserService service;
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        principalCollection.getPrimaryPrincipal();
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        return simpleAuthorizationInfo;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        String username = token.getUsername();
        User user = 对应数据库查询操作,可根据自己的代码书写即可;
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(user,user.getPassword(), ByteSource.Util.bytes(user.getSalt()),getName());
        return simpleAuthenticationInfo;
    }
}

第三:AuthFilter.shiro所有请求必须要走的过滤器


/**
 * shiro过滤器
 */
@Component("authFilter")
public class AuthFilter extends FormAuthenticationFilter {

    @Autowired
    JwtUtil jwtUtil;

    /**
     * 判断token是否为空、过期
     *
     * @param request
     * @param response
     * @param mappedValue
     * @return
     */
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
            String token = getRequestToken((HttpServletRequest) request);
            if (ObjectUtils.isNull(token)){
                return false;
            }
            if (StringUtils.isBlank(token)) {
                throw new CustomException(jwtUtil.getHeader()+"不能为空", HttpStatus.SC_UNAUTHORIZED);
            }
            Claims claims = jwtUtil.parseToken(token);
            if (ObjectUtils.isNull(claims) || jwtUtil.isTokenExpired(claims.getExpiration())) {
                throw new CustomException(jwtUtil.getHeader()+"token过期",HttpStatus.SC_UNAUTHORIZED);
            }
        return true;
    }

    /**
     * 上面的方法如果返回false,则接下来会执行这个方法,如果返回为true,则不会执行这个方法
     * 判断是否为登录url,进一步判断请求是不是post
     *
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        if (isLoginRequest(request, response)) {
            if (isLoginSubmission(request, response)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 获取请求中的token,首先从请求头中获取,如果没有,则尝试从请求参数中获取
     *
     * @param request
     * @return
     */
    private String getRequestToken(HttpServletRequest request) {
        String token = request.getHeader(jwtUtil.getHeader());
        if (StringUtils.isBlank(token)) {
            token = request.getParameter(jwtUtil.getHeader());
        }
        return token;
    }
}

第四:JwtUtil.负责JWT的创建和校验。

/**
 * JWT token 工具类,提供JWT生成,校验,工作
 */
@ConfigurationProperties(prefix = "dhb.jwt")
@Component
public class JwtUtil {
    private Logger logger = LoggerFactory.getLogger(getClass());
    private String secret;
    private Long expire;
    private String header;


    /**
     *
     * 生成JWT token
     * @param userId
     * @return
     */
    public String generateToken(Long userId) {
        Date nowDate = new Date();
        Date expireDate = new Date(nowDate.getTime() + expire * 1000);
        return Jwts.builder()
                .setHeaderParam("typ", "JWT")
                .setSubject(userId + "")
                .setIssuedAt(nowDate)
                .setExpiration(expireDate)
                .signWith(SignatureAlgorithm.HS256, secret)
                .compact();

    }

    /**
     *
     * 解析JWT token
     * @param token
     * @return
     */
    public Claims parseToken(String token) {
        try {

            return Jwts.parser()
                    .setSigningKey(secret)
                    .parseClaimsJws(token)
                    .getBody();
        } catch (Exception e) {
            logger.info("解析token出错");
            return null;
        }
    }

    /**
     *
     * 校验token是否过期
     * @param expiprationTime
     * @return
     */
    public boolean isTokenExpired(Date expiprationTime){
        return expiprationTime.before(new Date());
    }
    public String getSecret() {
        return secret;
    }

    public void setSecret(String secret) {
        this.secret = secret;
    }

    public Long getExpire() {
        return expire;
    }

    public void setExpire(Long expire) {
        this.expire = expire;
    }

    public String getHeader() {
        return header;
    }

    public void setHeader(String header) {
        this.header = header;
    }
}

写在最后:虽然看起来这有这四大步,但是回头看看自己花了好长时间才走到现在这样。从一开始的认识shiro的架构,简单的基本使用,到实际运用中踩的坑,以及为什么要用token,不用session,以及舍弃配置复杂的session和quartz集成管理。这期间,每一步自己都在想,我为什么要用某一个技术,在实际编码中如何做到不让最后集成起来很臃肿。

推荐对于平时自己测试接口的时候,使用PostMan或者Yapi,千万不要为了测一个小小的接口又去写页面之类的,这样会使你脱离工作重心,最后啥啥都没干好。

本专栏并没有提供相关完整的代码,不过,有一个前后端项目中整合了Shiro,如有需要,代码在这里

还是那句话:既然要做,就做的细致一点,对得起自己!

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
课程简介:历经半个多月的时间,Debug亲自撸的 “企业员工角色权限管理平台” 终于完成了。正如字面意思,本课程讲解的是一个真正意义上的、企业级的项目实战,主要介绍了企业级应用系统中后端应用权限的管理,其中主要涵盖了六大核心业务模块、十几张数据库表。 其中的核心业务模块主要包括用户模块、部门模块、岗位模块、角色模块、菜单模块和系统日志模块;与此同时,Debug还亲自撸了额外的附属模块,包括字典管理模块、商品分类模块以及考勤管理模块等等,主要是为了更好地巩固相应的技术栈以及企业应用系统业务模块的开发流程! 核心技术栈列表: 值得介绍的是,本课程在技术栈层面涵盖了前端和后端的大部分常用技术,包括Spring Boot、Spring MVC、Mybatis、Mybatis-Plus、Shiro(身份认证与资源授权跟会话等等)、Spring AOP、防止XSS攻击、防止SQL注入攻击、过滤器Filter、验证码Kaptcha、热部署插件Devtools、POI、Vue、LayUI、ElementUI、JQuery、HTML、Bootstrap、Freemarker、一键打包部署运行工具Wagon等等,如下图所示: 课程内容与收益: 总的来说,本课程是一门具有很强实践性质的“项目实战”课程,即“企业应用员工角色权限管理平台”,主要介绍了当前企业级应用系统中员工、部门、岗位、角色、权限、菜单以及其他实体模块的管理;其中,还重点讲解了如何基于Shiro的资源授权实现员工-角色-操作权限、员工-角色-数据权限的管理;在课程的最后,还介绍了如何实现一键打包上传部署运行项目等等。如下图所示为本权限管理平台的数据库设计图: 以下为项目整体的运行效果截图: 值得一提的是,在本课程中,Debug也向各位小伙伴介绍了如何在企业级应用系统业务模块的开发中,前端到后端再到数据库,最后再到服务器的上线部署运行等流程,如下图所示:
对于Spring Boot集成Shiro,你可以按照以下步骤进行操作: 1. 首先,在你的Spring Boot项目中添加Shiro的依赖。你可以在pom.xml文件中添加以下依赖关系: ```xml <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-starter</artifactId> <version>1.7.1</version> </dependency> ``` 2. 创建一个Shiro的配置类,用于配置Shiro的相关组件和属性。可以使用`@Configuration`注解来标记该类作为配置类,并使用`@EnableShiroAnnotation`注解来启用Shiro的注解支持。 ```java @Configuration @EnableShiroAnnotation public class ShiroConfig { // 配置Shiro的相关组件和属性 // ... } ``` 3. 在上述配置类中,可以配置Shiro的Realm、Session管理器、缓存管理器等组件。你可以根据自己的需求选择相应的实现类并进行配置。 ```java @Configuration @EnableShiroAnnotation public class ShiroConfig { @Bean public Realm realm() { // 配置自定义的Realm实现类 // ... return realm; } @Bean public SessionManager sessionManager() { // 配置自定义的Session管理器实现类 // ... return sessionManager; } @Bean public CacheManager cacheManager() { // 配置自定义的缓存管理器实现类 // ... return cacheManager; } // 其他配置项... } ``` 4. 在主配置类中,添加`@Import`注解来引入Shiro的配置类。 ```java @SpringBootApplication @Import(ShiroConfig.class) public class YourApplication { public static void main(String[] args) { SpringApplication.run(YourApplication.class, args); } } ``` 5. 在需要进行权限控制的地方,使用Shiro的注解来标记需要进行权限验证的方法或类。例如,可以使用`@RequiresRoles`注解来限制具有特定角色的用户才能访问方法。 ```java @RestController public class YourController { @RequiresRoles("admin") @GetMapping("/admin") public String admin() { return "Hello, admin!"; } } ``` 这样,你就成功地集成Spring Boot和Shiro,并可以进行基于角色的权限控制了。当然,以上只是一个简单的示例,你可以根据自己的需求进行更详细的配置和使用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值