`

39.1 Spring Boot Shiro权限管理【从零开始学Spring Boot】

阅读更多

 à悟空学院:https://t.cn/Rg3fKJD

学院中有Spring Boot相关的课程!点击「阅读原文」进行查看!

SpringBoot视频:http://t.cn/A6ZagYTi

Spring Cloud视频:http://t.cn/A6ZagxSR

SpringBoot Shiro视频:http://t.cn/A6Zag7IV

SpringBoot交流平台:https://t.cn/R3QDhU0

SpringData和JPA视频:http://t.cn/A6Zad1OH

SpringSecurity5.0视频:http://t.cn/A6ZadMBe

Sharding-JDBC分库分表实战http://t.cn/A6ZarrqS

分布式事务解决方案「手写代码」:http://t.cn/A6ZaBnIr

 

本节提供源代码,在最下面可以下载)距上一个章节过了二个星期了,最近时间也是比较紧,一直没有时间可以写博客,今天难得有点时间,就说说Spring Boot如何集成Shiro吧。这个章节会比较复杂,牵涉到的技术点也会比较,如果没有Spring Boot基础的还是建议先学习基础,不然此博客看起来会比较费劲。好了废话不都说了,还是开始我们的Spring Boot Shiro之旅吧。还是依照之前的风格,我们分解下我们的目标:

----------------------------------------------------------------

(1). Shiro简单介绍

(2). 集成Shiro核心分析

(3). ShiroSpring Boot

(4). 集成Shiro 进行用户授权

(5). Shiro缓存

(6). Shiro记住密码

(7). Shiro验证码

-------------------------------------------------------------------

 

 

 

(1). Shiro简单介绍

ShiroApache下的一个开源项目,我们称之为Apache Shiro。它是一个很易用与Java项目的的安全框架,提供了认证、授权、加密、会话管理,与 Spring Security 一样都是做一个权限的安全框架,但是与Spring Security 相比,在于 Shiro 使用了比较简单易懂易于使用的授权方式。

Apache Shiro 的三大核心组件 


 这里写图片描述<!--[endif]--> 
- Subject
当前用户操作 
- SecurityManager
用于管理所有的Subject 
- Realms
用于进行权限信息的验证,也是我们需要自己实现的。

我们需要实现RealmsAuthentication Authorization。其中 Authentication 是用来验证用户身份,Authorization 是授权访问控制,用于对用户进行的操作授权,证明该用户是否允许进行当前操作,如访问某个链接,某个资源文件等。

Apache Shiro 核心通过 Filter 来实现,就好像SpringMvc 通过DispachServlet 来主控制一样。 
既然是使用 Filter 一般也就能猜到,是通过URL规则来进行过滤和权限校验,所以我们需要定义一系列关于URL的规则和访问权限。

另外我们可以通过Shiro 提供的会话管理来获取Session中的信息。Shiro 也提供了缓存支持,使用 CacheManager 来管理。

官方网站:http://shiro.apache.org/ 

完整架构图: 



 

 

      Shiro是很强大的一个安全框架,这里只是抛装引玉下,还有很多的需要大家自己去学习Shiro

 

(2). 集成Shiro核心分析

      集成Shiro的话,我们需要知道Shiro框架大概的一些管理对象。

第一:ShiroFilterFactoryShiro过滤器工厂类,具体的实现类是:ShiroFilterFactoryBean,此实现类是依赖于SecurityManager安全管理器。

第二:SecurityManager,Shiro的安全管理,主要是身份认证的管理,缓存管理,cookie管理,所以在实际开发中我们主要是和SecurityManager进行打交道的,ShiroFilterFactory主要配置好了Filter就可以了。当然SecurityManager并进行身份认证缓存的实现,我们需要进行对应的编码然后进行注入到安全管理器中。

第三:Realm,用于身份信息权限信息的验证。

第四:其它的就是缓存管理,记住登录之类的,这些大部分都是需要自己进行简单的实现,然后注入到SecurityManagerShiro的安全管理器进行管理就好了。

 

(3). ShiroSpring Boot

      我们先编写一个无Shiro的简单的框架,在这个框架中我们可以访问到index,login,userInfo,userInfoAdd

      这个步骤对于有Spring Boot基础的就应该很简单了,在这里简单的介绍下:

(a) 新建一个maven java project,取名为spring-boot-shiro1

(b) pom.xml中引入基本依赖,在这里还没有引入shiro等的依赖:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

  <modelVersion>4.0.0</modelVersion>

 

  <groupId>com.kfit</groupId>

  <artifactId>spring-boot-shiro1</artifactId>

  <version>0.0.1-SNAPSHOT</version>

  <packaging>jar</packaging>

 

  <name>spring-boot-shiro1</name>

  <url>http://maven.apache.org</url>

 

  <properties>

    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

    <java.version>1.8</java.version>

  </properties>

   

    <!--

       spring boot 父节点依赖,

       引入这个之后相关的引入就不需要添加version配置,

       spring boot会自动选择最合适的版本进行添加。

     -->

    <parent>

       <groupId>org.springframework.boot</groupId>

       <artifactId>spring-boot-starter-parent</artifactId>

       <version>1.3.3.RELEASE</version>

    </parent>    

 

  <dependencies>

   

        <!-- spring boot web支持:mvc,aop... -->

       <dependency>

           <groupId>org.springframework.boot</groupId>

           <artifactId>spring-boot-starter-web</artifactId>

       </dependency>

      

       <!-- thmleaf模板依赖. -->

       <dependency>

         <groupId>org.springframework.boot</groupId>

         <artifactId>spring-boot-starter-thymeleaf</artifactId>

       </dependency>

   

  </dependencies>

</project>

在这里只引入了Spirng Bootweb依赖以及对thymleaf模板引擎的依赖。

(c) 编写网页文件:

index.html,login.html,userInfo.html,userInfoAdd.html

这个文件存在在src/main/resouces/templates, 这几个文件中都是简单的代码,只有登录界面中有账号和密码:

index.html

<!DOCTYPE html>

<html>

<head>

<meta charset="UTF-8" />

<title>Insert title here</title>

</head>

<body>

    <h3>index</h3>

</body>

</html>

 

login.html :

<!DOCTYPE html>

<html>

<head>

<meta charset="UTF-8" />

<title>Insert title here</title>

</head>

<body>

            错误信息:<h4 th:text="${msg}"></h4>

       <form action="" method="post">

           <p>账号:<input type="text" name="username" value="admin"/></p>

           <p>密码:<input type="text" name="password" value="123456"/></p>

           <p><input type="submit" value="登录"/></p>

       </form>

</body>

</html>

 

其它的页面都是简单的一个标签而已:

<h3>用户查询界面</h3>

<h3>用户添加界面</h3>

请自行编码。

 

(d)编写启动类

编写启动类com.kfit.App.java

package com.kfit;

 

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

 

/**

 * 启动类.

 * @author Angel(QQ:412887952)

 * @version v.0.1

 */

@SpringBootApplication

publicclass App {

   

    /**

     * 参数里VM参数设置为:

    -javaagent:.\lib\springloaded-1.2.4.RELEASE.jar -noverify

     * @param args

     */

    publicstaticvoid main(String[] args) {

       SpringApplication.run(App.class, args);

    }

   

}

这样类似的代码我们已经介绍很多了,没有什么可以过多的介绍了,

这时候我们右键run as 运行App.java类访问index,login页面,会报Error Page,因为我们还没编写Controller处理类呢。

(e)编写HomeController

com.kfit.root.controller新建HomeController类:

package com.kfit.root.controller;

 

import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

 

@Controller

publicclass HomeController {

   

    @RequestMapping({"/","/index"})

    public String index(){

       return"/index";

    }

   

    @RequestMapping(value="/login",method=RequestMethod.GET)

    public String login(){

       return"login";

    }

   

}

在这里我们并没有把UserInfo对应的处理也在页面进行编码了,因为之后我们创建了UserInfo之后,打算新建一个UserInfoController进行处理,所以这里就没有相应的userInfo的跳转处理。

这时候我们在运行我们的程序就应该可以访问index,login页面了。

到此这个小节就结束了,现在我们的程序还有问题,就是index页面在没有登录的时候,就可以进行访问了,我们希望是如果直接访问index页面,如果没有登录的话,直接跳转到login进行登录。

那么下一小节我们将会介绍如何在当前代码中集成shiro

如果在一篇博客中介绍整个的集成过程的话,可能会比较乱,另外就是也没法介绍的那么细致,所以博主决定还是分开进行讲解,这样大家会比较好理解。那么下一篇博客大家再见吧,我要先去健健身,回来接着写。

 

【视频&交流平台】

à悟空学院:https://t.cn/Rg3fKJD

学院中有Spring Boot相关的课程!点击「阅读原文」进行查看!

SpringBoot视频:http://t.cn/A6ZagYTi

Spring Cloud视频:http://t.cn/A6ZagxSR

SpringBoot Shiro视频:http://t.cn/A6Zag7IV

SpringBoot交流平台:https://t.cn/R3QDhU0

SpringData和JPA视频:http://t.cn/A6Zad1OH

SpringSecurity5.0视频:http://t.cn/A6ZadMBe

Sharding-JDBC分库分表实战http://t.cn/A6ZarrqS

分布式事务解决方案「手写代码」:http://t.cn/A6ZaBnIr

 

à Spring Boot交流平台

http://412887952-qq-com.iteye.com/blog/2321532

 

 ======================================

Spring Boot Shiro视频实战篇【已更新】

======================================

 

适合人群

有Spring Boot基础的人群。

 

使用技术

(1)spring boot(整合框架)

(2)spring mvc

(3)spring data jpa(持久化操作)

(4)shiro(安全框架)

(5)thymeleaf(模板引擎)

(6)ehcache(缓存管理)

(7)mysql(数据库)

(8)js/css/img(静态资源使用)

9kaptcha(验证码库)

 

课程目录

1. Spring Boot Shiro介绍

 

2. Spring Boot 搭建无Shiro的框架

 

3. Spring Boot Shiro拦截

 

4. Spring Boot Shiro身份认证准备工作

 

5. Spring Boot Shiro身份认证

 

6. Spring Boot Shiro权限控制

 

7. Spring Boot Shiro缓存

 

8. Spring Boot Shiro记住密码

 

9. Spring Boot Shiro登录成功之后下载favicon.ico

 

10. Spring Boot 在thymeleaf使用shiro标签

 

11. Spring Boot Shiro密码加密算法

 

12.Spring Boot Shiro使用JS-CSS-IMG

 

13. Spring Boot Shiro限制登录尝试次数

 

14.Spring Boot Shiro 验证码

  • 大小: 32 KB
  • 大小: 122.7 KB
分享到:
评论
20 楼 林祥纤 2017-10-22  
1988南墙之南 写道
1988南墙之南 写道
我的springboot+shiro 会初始化shiroconfig对象,home页也会调到登录页,可是点登陆就是死活不进realm的doGetAuthorizationInfo和doGetAuthenticationInfo,我在shiroconfig和realm都加了一堆断点,但是一个都没进去!!!搞了好久,不知道为啥
下面是代码
package top.threadlocal.shirotest.config;

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;

@Configuration
public class ShiroConfig {
    /**
     * ShiroFilterFactoryBean 处理拦截资源文件问题。
     * 注意:单独一个ShiroFilterFactoryBean配置是或报错的,以为在
     * 初始化ShiroFilterFactoryBean的时候需要注入:SecurityManager
     *
     Filter Chain定义说明
     1、一个URL可以配置多个Filter,使用逗号分隔
     2、当设置多个过滤器时,全部验证通过,才视为通过
     3、部分过滤器可指定参数,如perms,roles
     *
     */
    @Bean
    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager){
        System.out.println("ShiroConfiguration.shirFilter()");
        ShiroFilterFactoryBean shiroFilterFactoryBean  = new ShiroFilterFactoryBean();

        // 必须设置 SecurityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        //拦截器.
        Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>();


        filterChainDefinitionMap.put("/css/**","anon");
        filterChainDefinitionMap.put("/html/**","anon");
        filterChainDefinitionMap.put("/js/**","anon");
        filterChainDefinitionMap.put("/lib/css/**","anon");
        filterChainDefinitionMap.put("/lib/js/**","anon");
        filterChainDefinitionMap.put("/lib/fonts/**","anon");
        filterChainDefinitionMap.put("/static/**","anon");

        //配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了
        filterChainDefinitionMap.put("/logout", "logout");

        //<!-- 过滤链定义,从上向下顺序执行,一般将 /**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了;
        //<!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
        filterChainDefinitionMap.put("/**", "authc");

        // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
        shiroFilterFactoryBean.setLoginUrl("/logPage");
        // 登录成功后要跳转的链接
        shiroFilterFactoryBean.setSuccessUrl("/home");
        //未授权界面;
        shiroFilterFactoryBean.setUnauthorizedUrl("/403");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }


    @Bean
    public SecurityManager securityManager(){
        DefaultWebSecurityManager securityManager =  new DefaultWebSecurityManager();
        //设置realm.
        securityManager.setRealm(myShiroRealm());
        return securityManager;
    }


    /**
     * 身份认证realm;
     * (这个需要自己写,账号密码校验;权限等)
     * @return
     */
    @Bean
    public UserRealm myShiroRealm(){
        UserRealm myShiroRealm = new UserRealm();
//        myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());;
        return myShiroRealm;
    }


    /**
     *  开启shiro aop注解支持.
     *  使用代理方式;所以需要开启代码支持;
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }
}




package top.threadlocal.shirotest.config;

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 top.threadlocal.shirotest.entity.UserEntity;

public class UserRealm extends AuthorizingRealm {

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("权限配置-->MyShiroRealm.doGetAuthorizationInfo()");
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        UserEntity userinfo  = (UserEntity)principalCollection.getPrimaryPrincipal();
//        List<RoleEntity> roleList = roleService.userRoleListGet(userinfo.getUser_name());
//        List<PermissionEntity> permissionList = permissionService.userPermissionListGet(userinfo.getUser_name());
//        for(RoleEntity role:roleService.userRoleListGet(userinfo.getUser_name())){
//            authorizationInfo.addRole(role.getRoleCode());
//        }
//        for(PermissionEntity p:permissionList){
//            authorizationInfo.addStringPermission(p.getPermissionCode());
//        }
        return authorizationInfo;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("MyShiroRealm.doGetAuthenticationInfo()");
        //获取用户的输入的账号.
        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
        String username = usernamePasswordToken.getUsername();
        System.out.println(token.getCredentials());
        //通过username从数据库中查找 User对象,如果找到,没找到.
        //实际项目中,这里可以根据实际情况做缓存,如果不做,Shiro自己也是有时间间隔机制,2分钟内不会重复执行该方法
        UserEntity userinfo = new UserEntity();
        userinfo.setUsername("admin");
        userinfo.setPassword("admin");
        System.out.println("----->>userInfo="+userinfo);
        if(userinfo == null){
            return null;
        }
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                username, //用户名
                userinfo.getPassword(), //密码
//                ByteSource.Util.bytes(userEntity.getUser_name()+"_salt"),//salt=username+salt
                getName()  //realm name
        );
        return authenticationInfo;
    }
}



package top.threadlocal.shirotest.controller;

import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;

@Controller
class IndexController {

    @RequestMapping("/home")
    public String indexRoot() {
        System.out.println("index");
        return "/index.html";
    }

    @RequestMapping(value = "/logPage",method = RequestMethod.GET)
    public String logPage() {
        System.out.println("logPage");
        return "/html/login.html";
    }

    @RequestMapping(value = "/login",method = RequestMethod.POST)
    public String login(HttpServletRequest request, Map<String, Object> map) throws Exception {
        System.out.println("IndexController.login()");
        // 登录失败从request中获取shiro处理的异常信息。
        // shiroLoginFailure:就是shiro异常类的全类名.
        String exception = (String) request.getAttribute("shiroLoginFailure");

        System.out.println("exception=" + exception);
        String msg = "";
        if (exception != null) {
            if (UnknownAccountException.class.getName().equals(exception)) {
                System.out.println("UnknownAccountException -- > 账号不存在:");
                msg = "UnknownAccountException -- > 账号不存在:";
            } else if (IncorrectCredentialsException.class.getName().equals(exception)) {
                System.out.println("IncorrectCredentialsException -- > 密码不正确:");
                msg = "IncorrectCredentialsException -- > 密码不正确:";
            } else if ("kaptchaValidateFailed".equals(exception)) {
                System.out.println("kaptchaValidateFailed -- > 验证码错误");
                msg = "kaptchaValidateFailed -- > 验证码错误";
            } else {
                msg = "else >> " + exception;
                System.out.println("else -- >" + exception);
            }
        }
        map.put("msg", msg);
        // 此方法不处理登录成功,由shiro进行处理.
        return "/logPage";
    }
}


function login() {
    var remberMe;
    if($("#remberMe").prop("checked")){
        remberMe = 1;
    }else{
        remberMe = 0;
    }
    console.log('-------'+remberMe);
    $.ajax({
        url: '/login',
        dataType: 'json',
        type: 'post',
        async: false,
        cache: false,
        data:{
            remberMe: remberMe,
            username: $("#user_name").val(),
            password: $("#password").val()
        },
        success:function (response) {
            if (response.status == 'success'){
                alert("success");
                // window.location.href='../index.html';
            }
        },
        error:function (error) {
            console.log(error);
        }
    });
}




这样看不出来,你把代码整理下,发我邮箱吧
19 楼 1988南墙之南 2017-10-22  
1988南墙之南 写道
我的springboot+shiro 会初始化shiroconfig对象,home页也会调到登录页,可是点登陆就是死活不进realm的doGetAuthorizationInfo和doGetAuthenticationInfo,我在shiroconfig和realm都加了一堆断点,但是一个都没进去!!!搞了好久,不知道为啥
下面是代码
package top.threadlocal.shirotest.config;

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;

@Configuration
public class ShiroConfig {
    /**
     * ShiroFilterFactoryBean 处理拦截资源文件问题。
     * 注意:单独一个ShiroFilterFactoryBean配置是或报错的,以为在
     * 初始化ShiroFilterFactoryBean的时候需要注入:SecurityManager
     *
     Filter Chain定义说明
     1、一个URL可以配置多个Filter,使用逗号分隔
     2、当设置多个过滤器时,全部验证通过,才视为通过
     3、部分过滤器可指定参数,如perms,roles
     *
     */
    @Bean
    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager){
        System.out.println("ShiroConfiguration.shirFilter()");
        ShiroFilterFactoryBean shiroFilterFactoryBean  = new ShiroFilterFactoryBean();

        // 必须设置 SecurityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        //拦截器.
        Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>();


        filterChainDefinitionMap.put("/css/**","anon");
        filterChainDefinitionMap.put("/html/**","anon");
        filterChainDefinitionMap.put("/js/**","anon");
        filterChainDefinitionMap.put("/lib/css/**","anon");
        filterChainDefinitionMap.put("/lib/js/**","anon");
        filterChainDefinitionMap.put("/lib/fonts/**","anon");
        filterChainDefinitionMap.put("/static/**","anon");

        //配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了
        filterChainDefinitionMap.put("/logout", "logout");

        //<!-- 过滤链定义,从上向下顺序执行,一般将 /**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了;
        //<!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
        filterChainDefinitionMap.put("/**", "authc");

        // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
        shiroFilterFactoryBean.setLoginUrl("/logPage");
        // 登录成功后要跳转的链接
        shiroFilterFactoryBean.setSuccessUrl("/home");
        //未授权界面;
        shiroFilterFactoryBean.setUnauthorizedUrl("/403");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }


    @Bean
    public SecurityManager securityManager(){
        DefaultWebSecurityManager securityManager =  new DefaultWebSecurityManager();
        //设置realm.
        securityManager.setRealm(myShiroRealm());
        return securityManager;
    }


    /**
     * 身份认证realm;
     * (这个需要自己写,账号密码校验;权限等)
     * @return
     */
    @Bean
    public UserRealm myShiroRealm(){
        UserRealm myShiroRealm = new UserRealm();
//        myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());;
        return myShiroRealm;
    }


    /**
     *  开启shiro aop注解支持.
     *  使用代理方式;所以需要开启代码支持;
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }
}




package top.threadlocal.shirotest.config;

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 top.threadlocal.shirotest.entity.UserEntity;

public class UserRealm extends AuthorizingRealm {

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("权限配置-->MyShiroRealm.doGetAuthorizationInfo()");
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        UserEntity userinfo  = (UserEntity)principalCollection.getPrimaryPrincipal();
//        List<RoleEntity> roleList = roleService.userRoleListGet(userinfo.getUser_name());
//        List<PermissionEntity> permissionList = permissionService.userPermissionListGet(userinfo.getUser_name());
//        for(RoleEntity role:roleService.userRoleListGet(userinfo.getUser_name())){
//            authorizationInfo.addRole(role.getRoleCode());
//        }
//        for(PermissionEntity p:permissionList){
//            authorizationInfo.addStringPermission(p.getPermissionCode());
//        }
        return authorizationInfo;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("MyShiroRealm.doGetAuthenticationInfo()");
        //获取用户的输入的账号.
        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
        String username = usernamePasswordToken.getUsername();
        System.out.println(token.getCredentials());
        //通过username从数据库中查找 User对象,如果找到,没找到.
        //实际项目中,这里可以根据实际情况做缓存,如果不做,Shiro自己也是有时间间隔机制,2分钟内不会重复执行该方法
        UserEntity userinfo = new UserEntity();
        userinfo.setUsername("admin");
        userinfo.setPassword("admin");
        System.out.println("----->>userInfo="+userinfo);
        if(userinfo == null){
            return null;
        }
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                username, //用户名
                userinfo.getPassword(), //密码
//                ByteSource.Util.bytes(userEntity.getUser_name()+"_salt"),//salt=username+salt
                getName()  //realm name
        );
        return authenticationInfo;
    }
}



package top.threadlocal.shirotest.controller;

import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;

@Controller
class IndexController {

    @RequestMapping("/home")
    public String indexRoot() {
        System.out.println("index");
        return "/index.html";
    }

    @RequestMapping(value = "/logPage",method = RequestMethod.GET)
    public String logPage() {
        System.out.println("logPage");
        return "/html/login.html";
    }

    @RequestMapping(value = "/login",method = RequestMethod.POST)
    public String login(HttpServletRequest request, Map<String, Object> map) throws Exception {
        System.out.println("IndexController.login()");
        // 登录失败从request中获取shiro处理的异常信息。
        // shiroLoginFailure:就是shiro异常类的全类名.
        String exception = (String) request.getAttribute("shiroLoginFailure");

        System.out.println("exception=" + exception);
        String msg = "";
        if (exception != null) {
            if (UnknownAccountException.class.getName().equals(exception)) {
                System.out.println("UnknownAccountException -- > 账号不存在:");
                msg = "UnknownAccountException -- > 账号不存在:";
            } else if (IncorrectCredentialsException.class.getName().equals(exception)) {
                System.out.println("IncorrectCredentialsException -- > 密码不正确:");
                msg = "IncorrectCredentialsException -- > 密码不正确:";
            } else if ("kaptchaValidateFailed".equals(exception)) {
                System.out.println("kaptchaValidateFailed -- > 验证码错误");
                msg = "kaptchaValidateFailed -- > 验证码错误";
            } else {
                msg = "else >> " + exception;
                System.out.println("else -- >" + exception);
            }
        }
        map.put("msg", msg);
        // 此方法不处理登录成功,由shiro进行处理.
        return "/logPage";
    }
}


function login() {
    var remberMe;
    if($("#remberMe").prop("checked")){
        remberMe = 1;
    }else{
        remberMe = 0;
    }
    console.log('-------'+remberMe);
    $.ajax({
        url: '/login',
        dataType: 'json',
        type: 'post',
        async: false,
        cache: false,
        data:{
            remberMe: remberMe,
            username: $("#user_name").val(),
            password: $("#password").val()
        },
        success:function (response) {
            if (response.status == 'success'){
                alert("success");
                // window.location.href='../index.html';
            }
        },
        error:function (error) {
            console.log(error);
        }
    });
}

18 楼 qwfys200 2017-07-21  
总结的不错。
17 楼 林祥纤 2017-06-05  
Mpolaris 写道
不好意思,是我搞错了,将楼主的@Controller 注解换成了@RestController注解
在网上找的:
引用

@Controller和@RestController的区别?

官方文档:
@RestController is a stereotype annotation that combines @ResponseBody and @Controller.
意思是:
@RestController注解相当于@ResponseBody + @Controller合在一起的作用(之前也是看到这句话,以为他们可以互换使用了,结果还是有些差别的)

1)如果只是使用@RestController注解Controller,则Controller中的方法无法返回jsp页面,
配置的视图解析器InternalResourceViewResolver不起作用,返回的内容就是Return 里的内容。
例如:本来应该到success.jsp页面的,则其显示success.

2)如果需要返回到指定页面,则需要用 @Controller配合视图解析器InternalResourceViewResolver才行。

3)如果需要返回JSON,XML或自定义mediaType内容到页面,则需要在对应的方法上加上@ResponseBody注解。


接下来进入博主的第二篇


赞.
16 楼 Mpolaris 2017-06-04  
不好意思,是我搞错了,将楼主的@Controller 注解换成了@RestController注解
在网上找的:
引用

@Controller和@RestController的区别?

官方文档:
@RestController is a stereotype annotation that combines @ResponseBody and @Controller.
意思是:
@RestController注解相当于@ResponseBody + @Controller合在一起的作用(之前也是看到这句话,以为他们可以互换使用了,结果还是有些差别的)

1)如果只是使用@RestController注解Controller,则Controller中的方法无法返回jsp页面,
配置的视图解析器InternalResourceViewResolver不起作用,返回的内容就是Return 里的内容。
例如:本来应该到success.jsp页面的,则其显示success.

2)如果需要返回到指定页面,则需要用 @Controller配合视图解析器InternalResourceViewResolver才行。

3)如果需要返回JSON,XML或自定义mediaType内容到页面,则需要在对应的方法上加上@ResponseBody注解。


接下来进入博主的第二篇
15 楼 林祥纤 2017-06-03  
Mpolaris 写道
是一个spring-boot-debug的文档



??
14 楼 林祥纤 2017-06-03  
Mpolaris 写道
楼主,你能不能帮我看一下我的项目为什么不能访问静态页面啊,后台接口还是可以得,返回的结果也不是html.项目的相关信息我发在群里了,我查了好久了,真不知道哪出的问题。在此谢过来了


静态的话,是不是配置了anno或者authc之类的,过滤掉了。
13 楼 Mpolaris 2017-06-02  
是一个spring-boot-debug的文档
12 楼 Mpolaris 2017-06-02  
楼主,你能不能帮我看一下我的项目为什么不能访问静态页面啊,后台接口还是可以得,返回的结果也不是html.项目的相关信息我发在群里了,我查了好久了,真不知道哪出的问题。在此谢过来了
11 楼 林祥纤 2017-06-02  
Mpolaris 写道
请问楼主代码中
引用

@SpringBootApplication
publicclass App {
    /**
     * 参数里VM参数设置为:
    -javaagent:.\lib\springloaded-1.2.4.RELEASE.jar -noverify
     * @param args
     */
    publicstaticvoid main(String[] args) {
       SpringApplication.run(App.class, args);
    }
   }


参数设置在哪设置的
建这个项目需要spring插件吗



不用,可以忽略那个.在这里没啥用。
10 楼 Mpolaris 2017-06-02  
请问楼主代码中
引用

@SpringBootApplication
publicclass App {
    /**
     * 参数里VM参数设置为:
    -javaagent:.\lib\springloaded-1.2.4.RELEASE.jar -noverify
     * @param args
     */
    publicstaticvoid main(String[] args) {
       SpringApplication.run(App.class, args);
    }
   }


参数设置在哪设置的
建这个项目需要spring插件吗
9 楼 林祥纤 2017-06-02  
Mpolaris 写道
楼主,项目启动后报了404呀

main] com.spring_boot_shiro.App                : Started App in 3.764 seconds (JVM running for 4.28)
2017-06-01 17:32:32.145  INFO 5444 --- [nio-8090-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring FrameworkServlet 'dispatcherServlet'
2017-06-01 17:32:32.145  INFO 5444 --- [nio-8090-exec-1] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization started
2017-06-01 17:32:32.147  INFO 5444 --- [nio-8090-exec-1] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization completed in 2 ms


能给我说下为什么吗?



看看404的原因:
99. Spring Boot之Hello World访问404

另外看看是不是权限控制导致资源不可访问了。
8 楼 Mpolaris 2017-06-01  
楼主,项目启动后报了404呀

main] com.spring_boot_shiro.App                : Started App in 3.764 seconds (JVM running for 4.28)
2017-06-01 17:32:32.145  INFO 5444 --- [nio-8090-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring FrameworkServlet 'dispatcherServlet'
2017-06-01 17:32:32.145  INFO 5444 --- [nio-8090-exec-1] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization started
2017-06-01 17:32:32.147  INFO 5444 --- [nio-8090-exec-1] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization completed in 2 ms


能给我说下为什么吗?
7 楼 林祥纤 2017-03-31  
zwx198988 写道
楼主,请问怎么让shiro 管理多个Springboot工程,上面的例子只能正对一个Springboot,但springcloud 是微服务的。。


你只需要在gateway处理就好了!
6 楼 zwx198988 2017-03-31  
楼主,请问怎么让shiro 管理多个Springboot工程,上面的例子只能正对一个Springboot,但springcloud 是微服务的。。
5 楼 hxirui 2017-02-23  
只有我发现楼主的resources目录名称写错了吗?  根本跑不起来.
4 楼 林祥纤 2016-09-29  
HYX15517551511 写道
博主 您好 您的联系方式是多少 QQ QQ呢 有问题请教


加群:193341332
3 楼 HYX15517551511 2016-09-28  
博主 您好 您的联系方式是多少 QQ QQ呢 有问题请教
2 楼 林祥纤 2016-08-08  
charly21 写道
form 提交方式是 post , controller 接的时候却是 get[size=large][/size]


这里的get只是访问,post方法需要在下一章节才会编码,请认真阅读。
1 楼 charly21 2016-08-08  
form 提交方式是 post , controller 接的时候却是 get[size=large][/size]

相关推荐

Global site tag (gtag.js) - Google Analytics