shiro权限入门(一)

首先创建一个spring boot 项目(idea)

不多说,一路Next.

pom.xml文件

<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>1.3.1</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-cache</artifactId>
		</dependency>
		<!--  redis -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-redis</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid</artifactId>
			<version>1.1.0</version>
		</dependency>

		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-spring</artifactId>
			<version>1.4.0</version>
		</dependency>
	</dependencies>

application.properties 文件

spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=admin
#包别名
mybatis.typeAliasesPackage=com.shiro.pojo
#mapper文件路径
mybatis.mapperLocations=classpath:mapping/*.xml
#templates配置
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html

此时项目已经可以启动了

第一步,编写shiro配置文件

package com.shiro.Config;

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

import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * description:
 * author:fuLin.guo
 * Date:2018/12/6 0006 10:22
 */
@Configuration
public class ShiroConfig {
    @Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        System.out.println("---------------------Shiro拦截器工厂类注入开始");
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        //拦截器.
        Map<String,String> filterChainDefinitionMap = new LinkedHashMap<>();
        // 配置不会被拦截的链接 顺序判断
        filterChainDefinitionMap.put("/css/**", "anon");
        filterChainDefinitionMap.put("/fonts/**", "anon");
        filterChainDefinitionMap.put("/js/**", "anon");
        filterChainDefinitionMap.put("/favicon.ico", "anon");
        // 加入不需要拦截的路径, 比如登录接口
        filterChainDefinitionMap.put("/toLogin", "anon");
        //配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了
        filterChainDefinitionMap.put("/logout", "logout");

        //<!-- 过滤链定义,从上向下顺序执行,一般将/**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了;
        //<!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
        filterChainDefinitionMap.put("/**", "authc");
        // 如果不设置默认会自动寻找Web工程根目录下的"/login.html"页面
        shiroFilterFactoryBean.setLoginUrl("/login");
        // 登录成功后要跳转的链接
        shiroFilterFactoryBean.setSuccessUrl("/index");
        //未授权界面;
        shiroFilterFactoryBean.setUnauthorizedUrl("/toerror");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

    /**
     * 身份认证realm;
     * (这个需要自己写,账号密码校验;权限等)
     * @return
     */
    @Bean
    public MyShiroRealm myShiroRealm(){
        MyShiroRealm myShiroRealm = new MyShiroRealm();
        // TODO 测试,我没有开启加密规则
//        myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher()); //设置加密规则
        return myShiroRealm;
    }

    @Bean
    public SecurityManager securityManager(){
        DefaultWebSecurityManager securityManager =  new DefaultWebSecurityManager();
        //设置Realm
        securityManager.setRealm(myShiroRealm());
        // TODO 注入缓存管理器  后期使用redis
//        securityManager.setCacheManager(ehCacheManager());//这个如果执行多次,也是同样的一个对象;
        return securityManager;
    }
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor
                = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }
    /**
     * 凭证匹配器
     * (由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了
     *  所以我们需要修改下doGetAuthenticationInfo中的代码)
     * @return
     */
    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher(){
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName("md5");//散列算法:这里使用MD5算法;
        hashedCredentialsMatcher.setHashIterations(2);//散列的次数,比如散列两次,相当于 md5(md5(""))
        return hashedCredentialsMatcher;
    }
}

第二部,编写自定义realm

package com.shiro.Config;

import com.shiro.pojo.UserInfo;
import com.shiro.service.UserInfoManager;
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 javax.annotation.Resource;


/**
 * description:自定义权限匹配和账号密码匹配
 * author:fuLin.guo
 * Date:2018/12/6 0006 10:27
 */
public class MyShiroRealm extends AuthorizingRealm {

    @Resource
    private UserInfoManager userInfoManager;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        System.out.println("授权开始============");
        String username =(String) principals.getPrimaryPrincipal();
        System.out.println("授权用户名称:" + username);
        // TODO 此处给所有路径权限
        authorizationInfo.addRole("admin");
        authorizationInfo.addStringPermission("/*");
        /*List<RoleInfo> roleListByUserId = userInfoManager.getRoleListByUserId(user.getId());
        for (RoleInfo role :roleListByUserId ){
            authorizationInfo.addRole(role.getRolename());
           *//* for (Permission permission :role.getPermissions()){
                authorizationInfo.addStringPermission(permission.getPermission());
            }*//*
        }*/
        return authorizationInfo;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

        System.out.println("开始身份认证:===》");
        //获取用户的输入的账号.
        UsernamePasswordToken token1 = (UsernamePasswordToken) token;
        String user = token1.getUsername();
        String pass = String.valueOf(token1.getPassword());
        System.out.println("用户输入的账号密码===>>:"+user+","+pass);
        //通过username从数据库中查找 User对象,如果找到,s没找到.
        //实际项目中,这里可以根据实际情况做缓存,如果不做,Shiro自己也是有时间间隔机制,2分钟内不会重复执行该方法
        UserInfo userInfo = new UserInfo(); // 实际操作需要从数据库中获取用户对象
        userInfo.setUsername("guo");
        userInfo.setPassword("123");
        if (null == userInfo) {
            System.out.println("====> 用户找不到");
            throw new UnknownAccountException();
        }
        // TODO 如果有停用或者离职等状态 继续判断
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                userInfo.getUsername(), //数据库中的用户名
                userInfo.getPassword().toCharArray(), //数据库中的密吗,此处没有加盐
                getName()  //realm name
        );
        System.out.println("认证完毕==============");
        return authenticationInfo;
    }
}

第三步,创建登录接口

package com.shiro.controller;

import com.shiro.pojo.UserInfo;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * description:
 * author:fuLin.guo
 * Date:2018/12/7 0007 10:09
 */
@Controller
@RequestMapping("/")
public class IndexController {

    @RequiresPermissions(value = "/*")
    @RequestMapping("/index")
    public String index(){
        System.out.println("go   to   index.......................");
        return "index";
    }
    @RequestMapping("/toerror")
    public String toerror(){
        System.out.println("go   to   403.......................");
        return "error";
    }
    @RequestMapping("/login")
    public String login(){
        System.out.println("go   to   login.......................");
        return "login";
    }

    @RequestMapping("/toLogin")
    public String toLogin(UserInfo userInfo){
        System.out.println("tologin...用户输入密码为:"+userInfo.getPassword());
        //使用最常见的用户名密码的方式
        AuthenticationToken token = new UsernamePasswordToken(
                userInfo.getUsername(), userInfo.getPassword());
        //获取Subject对象
        Subject subject = SecurityUtils.getSubject();
        System.out.println("登录验证开始.......");
        try {
            //传入上一步骤创建的token对象,登录,即进行身份验证操作。
            subject.login(token);
        } catch ( UnknownAccountException uae ) {
            // TODO 实际情况不需要设置s ,采用全局异常拦截器
            System.out.println("用户名未知");
        } catch ( IncorrectCredentialsException ice ) {
            System.out.println("凭据不正确,例如密码不正确 ...");
        } catch ( LockedAccountException lae ) {
            System.out.println("用户被锁定,例如管理员把某个用户禁用...");
        } catch ( ExcessiveAttemptsException eae ) {
            System.out.println("尝试认证次数多余系统指定次数 ...");
        } catch ( AuthenticationException ae ) {
            System.out.println("其他未指定异常");
        }
        //验证是否登录成功
        if(subject.isAuthenticated()){
            return "redirect:/index";
        }else{
            return "redirect:/login";
        }
    }
}

第四步,编写前端页面

第五步,启动

第一次, 访问http://localhost:8080/toLogin?username=guo&password=123234

密码写错

如果此时我不是用的打印方法,而是抛的异常等等..下面的就不会打印了

第二次,访问http://localhost:8080/toLogin?username=guo&password=123

密码正确

完成!

此时一个最简单基本的已经形成了.

spring boot 启动彩蛋!

在resources目录下创建banner.txt

然后复制以下代码保存即可


//                          _ooOoo_                               //
//                         o8888888o                              //
//                         88" . "88                              //
//                         (| ^_^ |)                              //
//                         O\  =  /O                              //
//                      ____/`---'\____                           //
//                    .'  \\|     |//  `.                         //
//                   /  \\|||  :  |||//  \                        //
//                  /  _||||| -:- |||||-  \                       //
//                  |   | \\\  -  /// |   |                       //
//                  | \_|  ''\---/''  |   |                       //
//                  \  .-\__  `-`  ___/-. /                       //
//                ___`. .'  /--.--\  `. . ___                     //
//             ."" '<  `.___\_<|>_/___.'  >'"".                   //
//            | | :  `- \`.;`\ _ /`;.`/ - ` : | |                 //
//            \  \ `-.   \_ __\ /__ _/   .-` /  /                 //
//      ========`-.____`-.___\_____/___.-`____.-'========         //
//                           `=---='                              //
//      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^        //
//                  佛祖保佑       永不宕机     永无BUG              //

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值