shiro授权和认证(二)

1、盐散列次数以及散列关系
 public static void main(String[] args){
//        Md5Hash md5Hash = new Md5Hash("abc");
//
//        System.out.println("散列后的结果:"+md5Hash);
        
        //为什么要加盐?  给这个密码再添加一层保障
        //为了让密码更加安全  更加不容易被破解

        Md5Hash md5Hash1 = new Md5Hash("abc", "123");
        System.out.println("加盐散列之后的值:"+md5Hash1);

        Md5Hash md5Hash2 = new Md5Hash("123abc");
        System.out.println("加盐散列之后的值:"+md5Hash2);

        //再看下多次散列的问题
        Md5Hash md5Hash = new Md5Hash("123", "", 2);
        System.out.println("加盐+次数构成的值:"+md5Hash);

        Md5Hash md5Hash3 = new Md5Hash("123");
        Md5Hash md5Hash4 = new Md5Hash(md5Hash3);
        System.out.println("翻译后的值:"+md5Hash4);
    }
2、将数据库的密码改成盐+密码散列后的值
  Md5Hash md5Hash1 = new Md5Hash("123", "abc");
        System.out.println("加盐散列之后的值:"+md5Hash1);
3、重新定义realm
public class MyRealm extends AuthorizingRealm {

    private UserDAO userDAO=new UserDAO();

    @Override
    public String getName() {
        return "MyRealm";
    }

    /**
     *这个方法是用来进行认证的
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //第一步:通过token获取到用户数据
        String userName = (String) authenticationToken.getPrincipal();
        //第二步:通过用户名 去数据库查询用户对象
        User user=null;
        try {
            user = userDAO.findUserByName(userName);
            System.out.println("从数据库查询出来的数据是:"+user);
        } catch (Exception e) {
            System.out.println("查询失败:"+e.fillInStackTrace());
        }
        if(null==user){   //说明数据库里面没有查询出数据来
            return null;
        }
         SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(
                user.getUserName(),              //用户名
                user.getPassword(),               //密码
                ByteSource.Util.bytes(user.getSalt()),   //这个是从数据库获取的盐
                getName());             //realm的名字
        return simpleAuthenticationInfo;
    }
    /**
     * 做用户授权的
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }
}
4、编写配置文件
[main]
#定义凭证匹配器
credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
#散列算法
credentialsMatcher.hashAlgorithmName=md5
#散列次数
credentialsMatcher.hashIterations=1

#将凭证匹配器设置到realm
customRealm=com.test.shiro.md5.MyRealm
customRealm.credentialsMatcher=$credentialsMatcher
securityManager.realms=$customRealm
5、代码授权

shiro中授权的方式有哪些

1、注解授权

2、过滤器授权

3、页面授权

4、代码授权

用户要授权必须是要在认证的基础上才能授权

问题:在哪里授权?

 if(subject.isPermitted("user:select")){
            System.out.println("admin....");
        }

        //表示的是一个一个判断 用户是否具有 某一个权限 (返回的是数组)
        boolean[] permitted = subject.isPermitted("", "", "");
        //表示的是一个一个判断 用户是否具有 某一个权限 (返回的是数组)
        subject.isPermitted(new ArrayList<Permission>());

        //玩下角色 (一个一个判断是否具有某一个角色)
        subject.hasRoles(new ArrayList<String>());
        subject.hasRole("");   //判断是否具有 某一个角色
        subject.hasAllRoles(new ArrayList<String>());  //判断是否具有所有权限

6、SpringBoot整合shiro

6.1、导包
 <!-- <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
      <!--  <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.1</version>
        </dependency>-->

       <!-- <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>-->

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <!--导入的是spring对shiro的支持包-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.0</version>
        </dependency>
6.2、配置模板引擎的配置(application.properties)
#配置模板引擎
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.mode=HTML5
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.cache=false
6.3、编写login.html页面
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

   <form action="/login" method="post">
       用户名:<input  type="text" name="userName"/><span th:text="${userNameError}"></span><br>
       密码:<input type="password" name="password"><span th:text="${passwordError}"></span><br>
       <input type="submit" value="登陆">
   </form>

</body>
</html>
6.4、编写index.html页面
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

   this is index Page And you?

</body>
</html>
6.5、编写ShiroConfig的配置文件
@SpringBootConfiguration
public class ShiroConfig {

    private Logger logger= LoggerFactory.getLogger(ShiroConfig.class);

    //配置咋们的过滤器拦截请求
    @Bean
     public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){
         ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
         logger.info("shiro的过滤器执行了.....");

         //配置如果认证没有通过的话 那么跳转的这个页面
         shiroFilterFactoryBean.setLoginUrl("/toLogin");


         Map<String,String> maps=new LinkedHashMap<>();
         //第一个参数是路劲  第二个参数是过滤器的名字
        /**
         * 常见的过滤器的名字以及含义
         * /**:当前以及目录和后面的所有子目录全部都匹配上
         *       127.0.0.1:8080/bobo     127.0.0.1:8080/bobo/xiaobobo
         * /* :这个相当于只是匹配当前这一级的节点   127.0.0.1:8080/bobo
         *      127.0.0.1:8080/bobo/xiaobobo
         * authc:认证的过滤器
         * anon: 表示的是/toIndex这个请求 不认证就可以访问 (匿名访问)
         *        maps.put("/toIndex","anon");
         * logout:登陆过滤器
         *        maps.put("/logout","logout")
         * perms:权限控制的
         * roles:具有某一个角色才能访问
         *
         * 注意事项:  /** 这个配置一定是最后 一个
         *
         */
         //maps.put("/toIndex","anon");  //表示的是不需要认证就可以访问

        maps.put("/login","anon");  //访问请求的地址
        maps.put("/**","authc");   //所有的请求都必须在用户认证之后才能访问


         shiroFilterFactoryBean.setFilterChainDefinitionMap(maps);

         //设置这个安全管理器
        shiroFilterFactoryBean.setSecurityManager(securityManager);
         return shiroFilterFactoryBean;
     }


    //配置的是安全管理器
    @Bean
    public DefaultWebSecurityManager securityManager(@Qualifier("myRealm") MyRealm myRealm){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //设置校验的realm对象
        logger.info("securityManager的过滤器执行了.....");
        securityManager.setRealm(myRealm);
        return securityManager;
    }



    //配置的是realm
    @Bean
    public MyRealm myRealm(){
        MyRealm myRealm = new MyRealm();
        logger.info("myRealm的过滤器执行了.....");
        return myRealm;
    }

}

6.6、controller的编写
@Controller
public class UserController {

    private Logger logger= LoggerFactory.getLogger(UserController.class);

    @RequestMapping("/toLogin")
    public String toLogin(){
        return "login";
    }

    /**
     * 跳转到Index页面的方法
     * @return
     */
    @RequestMapping("toIndex")
    public String toIndex(){
      return "index";
    }


    /**
     * 登陆的方法
     * @return
     */
    @RequestMapping(value = "login")
    public String login(User user, Model model){
         //封装成请求对象
        UsernamePasswordToken token = new UsernamePasswordToken(user.getUserName(), user.getPassword());
        //获取登陆的主体对象
        Subject subject = SecurityUtils.getSubject();
        //登陆
        try{
            subject.login(token);
        }catch (UnknownAccountException err){  //用户名不对
            logger.error("用户名不对");
            model.addAttribute("userNameError","用户名不对");
            return "login";
        }catch (IncorrectCredentialsException err){ //说明是密码不对
            logger.error("密码不对");
            model.addAttribute("passwordError","密码不对");
            return "login";
        }catch (Exception err){
            logger.error("其他问题造成登陆失败:"+err.fillInStackTrace());
            model.addAttribute("otherError","其他问题造成登陆失败");
            return "login";
        }
       return "index";
    }
}
6.7、Realm的编写
public class MyRealm extends AuthorizingRealm {

    @Override
    public String getName() {
        return "MyRealm";
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //第一步:获取用户名
        String userName= (String) authenticationToken.getPrincipal();
        //通过用户名查询用户对象
        if(!(userName.equals("admin"))){
           return null;
        }
        //假设查询出来了
        User user = new User(1, "admin", "123");
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(user.getUserName(), user.getPassword(), getName());

        return simpleAuthenticationInfo;
    }
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }
}
6.8、理解图

在这里插入图片描述

7、退出的问题
7.1、在页面上编写退出按钮
<a href="/logout">退出</a>
7.2、在全局的过滤器中进行登出过滤器的配置
 maps.put("/logout","logout");  //这个就是退出功能
8、密码散列的问题
8.1、在配置文件申明凭证匹配器
//配置密码散列的问题
    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher(){
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        //这里就是设置散列的方法的地方
        hashedCredentialsMatcher.setHashAlgorithmName("MD5");
        //设置的是散列的次数
        hashedCredentialsMatcher.setHashIterations(1);
        return hashedCredentialsMatcher;
    }
8.2、改造realm让他支持盐
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //第一步:获取用户名
        String userName= (String) authenticationToken.getPrincipal();
        //通过用户名查询用户对象
        if(!(userName.equals("admin"))){
           return null;
        }
        //假设查询出来了
        User user = new User(1, "admin", "e99a18c428cb38d5f260853678922e03");
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(
                user.getUserName(),
                user.getPassword(),
                ByteSource.Util.bytes("abc")
                ,getName());
        return simpleAuthenticationInfo;
    }
9、在首页显示用户信息的问题
9.1、通过代码实现在首页显示用户信息

改造 realm

 @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //第一步:获取用户名
        String userName= (String) authenticationToken.getPrincipal();
        //通过用户名查询用户对象
        if(!(userName.equals("admin"))){
           return null;
        }
        //假设查询出来了
        User user = new User(1, "admin", "e99a18c428cb38d5f260853678922e03");
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(
                user,
                user.getPassword(),
                ByteSource.Util.bytes("abc")
                ,getName());

        return simpleAuthenticationInfo;
    }

改造Cotnroller

 public String login(User user, Model model){
         //封装成请求对象
        UsernamePasswordToken token = new UsernamePasswordToken(user.getUserName(), user.getPassword());
        //获取登陆的主体对象
        Subject subject = SecurityUtils.getSubject();
        //登陆
        try{
            subject.login(token);
        }catch (UnknownAccountException err){  //用户名不对
            logger.error("用户名不对");
            model.addAttribute("userNameError","用户名不对");
            return "login";
        }catch (IncorrectCredentialsException err){ //说明是密码不对
            logger.error("密码不对");
            model.addAttribute("passwordError","密码不对");
            return "login";
        }catch (Exception err){
            logger.error("其他问题造成登陆失败:"+err.fillInStackTrace());
            model.addAttribute("otherError","其他问题造成登陆失败");
            return "login";
        }
        //首页要显示用户信息
        //获取用户信息
        //这个方法返回的数据 实际上就是 realm中认证的SimpleAuthticationInfo的第一个参数的数据
        User user1= (User) SecurityUtils.getSubject().getPrincipal();
        model.addAttribute("user",user);
       return "index";
    }

改在index.html文件

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

   欢迎<span th:text="${user.userName}"></span>大爷再次回来.....
   this is index Page And you? <br>

   <a href="/logout">退出</a>

</body>
</html>
10、授权有很多方式

代码授权

10.1过滤器授权

需求:假设在我的首页有一个按钮 这个按钮访问后台数据的时候 addUser接口这个接口必须要用户具有 user:add权限才能访问

1、在realm中查询用户的权限和角色放到缓存中

 @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //第一步:先获取用户名
        User user= (User) principalCollection.getPrimaryPrincipal();
        //第二步:通过用户名查询数据库  当前用户具有的权限  以及角色
        // ....
        // ...
        Set<String> perms=new HashSet<>();
        perms.add("ad:add");

        Set<String> roles=new HashSet<>();
        roles.add("seller");


        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(roles);
        simpleAuthorizationInfo.setStringPermissions(perms);
        return simpleAuthorizationInfo;
    }

2、在HTML页面上设置访问元素

 <a href="/addUser">添加用户</a>

3、在配置文件中配置过滤器授权

maps.put("/addUser","perms[user:add]"); //要请求这个地址 用户必
10.2、注解授权

简单的、它要写个注解就可以了

1、在配置文件中配置aop对注解的支持

  //下面配置AOP对注解的支持(也就是shiro中注解的支持)
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(
            @Qualifier("securityManager") DefaultWebSecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }
//这个是目标过滤器的生命周期
    @Bean
    @ConditionalOnMissingBean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }

2、在方法上使用注解来完成权限的判断

  @RequestMapping("toDelete")
    @RequiresPermissions({"user:delete"})  //要访问当前的方法必须具有user:delete的权限才能访问
    //@RequiresRoles({"seller"})
    public String toDelete(){
        return "delete";
    }
10.3、HTML页面上基于Thymeleaf的支持

1、导包

<!--导入thymeleaf对shiro的支持包-->
        <dependency>
            <groupId>com.github.theborakompanioni</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>2.0.0</version>
        </dependency>

2、配置方言

  /*配置shiro-dialect这个方言*/
    @Bean
    public ShiroDialect shiroDialect(){
        return new ShiroDialect();
    }

3、使用shiro的标签

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
      xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
   欢迎<span th:text="${user.userName}"></span>大爷再次回来.....
   this is index Page And you? <br>
   <a href="/logout">退出</a><br>

   <hr>
   <a href="/addUser">添加用户(测试过滤器授权)</a>
   <br>
   <a href="/toDelete">用户删除(测试注解授权)</a>

   <!--下面玩下shiro标签库中的标签-->
   <!--<shiro:authenticated>
       <span>
           用户的身份验证是成功的
       </span>
   </shiro:authenticated>

   <shiro:guest>
       <span>你是游客</span>
   </shiro:guest>

   <shiro:hasPermission name="user:add">
        <span>用户必须具有某一个权限才能访问</span>
   </shiro:hasPermission>

   <shiro:hasAllRoles name="buyer,seller">
       <span>拥有某一个角色下面才显示</span>
   </shiro:hasAllRoles>

   <shiro:lacksPermission>
       <span>没有某一个权限的时候才能访问</span>
   </shiro:lacksPermission>

   <shiro:lacksRole name="xxx">
        <span>没有某一个角色的时候才能访问</span>
   </shiro:lacksRole>


   <shiro:notAuthenticated>
       <span>没有认证通过才能显示</span>
   </shiro:notAuthenticated>
-->
   <hr>
   <!--下面就是显示用户信息的-->
   <shiro:principal property="userName"/> <br>
   <!--下面这个标签就表示的是用户已经登陆-->
   <shiro:user>
       <label>欢迎[<shiro:principal property="userName"/>]登陆</label>
   </shiro:user>
</body>
</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值