Spring整合shiro认证

时间:2019-09-18
本文章向大家介绍Spring整合shiro认证,主要包括Spring整合shiro认证使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

1.需要的依赖

<dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.1.3</version>
        </dependency>
        <dependency>
            <groupId>commons-collections</groupId>
            <artifactId>commons-collections</artifactId>
            <version>3.2.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.2.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-web</artifactId>
            <version>1.2.2</version>
        </dependency>
        <dependency>
            <groupId>net.sf.ehcache</groupId>
            <artifactId>ehcache-core</artifactId>
            <version>2.6.8</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-ehcache</artifactId>
            <version>1.2.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-quartz</artifactId>
            <version>1.2.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.2.2</version>
        </dependency>

2.配置代理类

在web.xml中配置shiro与Spring集成需要的ShiroFilter代理类

    <!-- shiro过虑器,DelegatingFilterProx会从spring容器中找shiroFilter -->
    <filter>
        <filter-name>shiroFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        <init-param>
            <param-name>targetFilterLifecycle</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>shiroFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <welcome-file-list>
        <welcome-file>/index.jsp</welcome-file>
    </welcome-file-list>

3.创建spring-shiro配置文件

需要定义的bean为:

  • Realm

  • securityManager

  • shirofilter

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:mvc="http://www.springframework.org/schema/mvc"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
                            http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
                            http://www.springframework.org/schema/context
                            http://www.springframework.org/schema/context/spring-context-3.1.xsd
                            http://www.springframework.org/schema/mvc
                            http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
    
        <!--配置自定义的realm-->
        <bean id="userRealm" class="cn.edu.neusoft.realm.UserRealm">
            <property name="userService" ref="userServiceImpl"/>
        </bean>
    
        <!--配置安全管理器-->
        <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
            <property name="realm" ref="userRealm"/>
        </bean>
    
        <!--定义shiro过滤器-->
        <!-- 定义ShiroFilter -->
        <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
            <property name="securityManager" ref="securityManager"/>
            <property name="loginUrl" value="/user/login"/>
            <property name="unauthorizedUrl" value="/nopermission.jsp"/>
            <property name="filterChainDefinitions">
                <value>
                    /user/test=anon
                    /assets/**=anon
                    /**=authc
                </value>
            </property>
        </bean>
    
    </beans>

需要注意:这里的shiroFilter和web.xml中配置的shiroFilter代理类名称必须一致,而且注意要将spring-shiro的配置文件在容器初始化的时候加载进来。

4.自定义Realm

需要继承AuthorizingRealm这个类并实现其中的方法,重写getName方法;

注入service时候使用的set方法进行注入,@setter为lombok插件省略getter setter;

package cn.edu.neusoft.realm;

import cn.edu.neusoft.entity.User;
import cn.edu.neusoft.service.UserService;
import lombok.Setter;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;

/**
 * @author Chen
 * @create 2019-04-30 15:27
 */
public class UserRealm extends AuthorizingRealm {
    @Setter
    private UserService userService;

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

    /**
     * 授权
     *
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }

    /**
     * 认证
     *
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //从token中获取登录的用户名, 查询数据库返回用户信息
        String username = (String) token.getPrincipal();
        User user = userService.getUserByUsername(username);

        if (user == null) {
            return null;
        }
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), getName());
        return info;
    }

}

5.Controller方法:

这里解释一下,使用了authc拦截器,当我们在spring-shiro.xml文件配置的登录地址和请求的登录地址一致时,有请求尽力啊,会判断用户是否登录了,如果登录的就放行,如果没有登录,这个拦截器会尝试获取请求中的帐号和密码,然后进行对比,如果对比正确,直接执行登录,反之,抛异常,返回到authc.loginUrl指定的路径。

@RequestMapping("login")
    public String login(Model model, HttpServletRequest req){
        //如果登陆失败从request中获取认证异常信息,shiroLoginFailure就是shiro异常类的全限定名
        String exceptionClassName = (String) req.getAttribute("shiroLoginFailure");
        //根据shiro返回的异常类路径判断,抛出指定异常信息
        if(exceptionClassName!=null){
            if (UnknownAccountException.class.getName().equals(exceptionClassName)) {
                //最终会抛给异常处理器

                model.addAttribute("errorMsg", "账号不存在");
            } else if (IncorrectCredentialsException.class.getName().equals(
                    exceptionClassName)) {
                model.addAttribute("errorMsg", "用户名/密码错误");
            } else {
                //最终在异常处理器生成未知错误.
                model.addAttribute("errorMsg", "其他异常信息");
            }
        }
        //此方法不处理登陆成功(认证成功),shiro认证成功会自动跳转到上一个请求路径
        //登陆失败还到login页面
        return "admin/login";
    }

原文地址:https://www.cnblogs.com/chen88/p/11538362.html