在Spring + SpringMVC + mybatis架构的项目基础上集成Shiro

Shiro使用五步走:

 一、pom文件引入shiro依赖

<dependency>
  <groupId>org.apache.shiro</groupId>
  <artifactId>shiro-all</artifactId>
  <version>1.2.5</version>
</dependency>

二、在Web.xml中配置shiroFilter

<!--shiro配置-->
<filter>
    <filter-name>shiroFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
    <filter-name>shiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

 

三、在Spring配置文件中引入shiro的配置文件spring-shiro.xml

<!--引入spring-shiro-->
<import resource="spring-shiro.xml"/>

spring-shiro.xml文件的内容:

<?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:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager" />
        <property name="loginUrl" value="login" />
        <property name="successUrl" value="welcome" />
        <property name="unauthorizedUrl" value="/login" />
        <property name="filters">
            <util:map>
                <entry key="authc" value-ref="formAuthenticationFilter"/>
            </util:map>
        </property>
        <property name="filterChainDefinitions">
            <value>
                /static/**  = anon
                /plugins/** = anon
                /login*     = anon
                /logout     = logout
                /**         = authc
                /**         = user
            </value>
        </property>

    </bean>

    <!--创建shiro的安全管理器的对象-->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="myShiroRealm" />

        <!--声明会话管理器属性-->
        <!--<property name="sessionManager" ref="sessionManager"></property>-->
        <!--声明rememberMe-->
        <property name="rememberMeManager" ref="rememberMeManager"></property>
    </bean>

    <!-- 项目自定义的Realm -->
    <bean id="myShiroRealm" class="com.blueice.shiro.MyShiroRealm">
        <property name="credentialsMatcher" ref="credentialsMatcher"/>
        <property name="cachingEnabled" value="false"/>
    </bean>
    <!-- 凭证匹配器(加密器) -->
    <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
        <!--<constructor-arg ref="shiroCacheManager" />-->
        <property name="hashAlgorithmName" value="md5" />
        <property name="hashIterations" value="3" />
        <!--storedCredentialsHexEncoded默认是true,此时用的是密码加密用的是Hex编码;false时用Base64编码-->
        <property name="storedCredentialsHexEncoded" value="true" />
    </bean>

    <!-- 基于表单认证的过滤器 -->
    <bean id="formAuthenticationFilter" class="org.apache.shiro.web.filter.authc.FormAuthenticationFilter"/>

    <!-- 这是干啥的?? -->
    <!--<bean id="lifecycleBeanPostProcessor"
          class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>-->

    <!--记住我的配置-->
    <!--声明cookie对象-->
    <bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
        <constructor-arg value="rememberMe"></constructor-arg>
        <!--只有http的链接才能使用cookie-->
        <property name="httpOnly" value="true"></property>
        <!--cookie的失效时间30天,单位是秒-->
        <property name="maxAge" value="2592000"></property>
    </bean>
    <!--声明记住我的管理器对象-->
    <bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
        <property name="cookie" ref="rememberMeCookie"></property>
    </bean>


</beans>

四、继承AuthorizingRealm,自定义授权和认证信息

package com.blueice.shiro;

import com.blueice.entity.SysUser;
import com.blueice.services.IndexService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;

import javax.annotation.Resource;
import java.text.ParseException;
import java.util.*;

/**
 * @desctiption 实现自己的JDBC Realm
 * @author shaoz
 * @date 2020-08-17 14:12
 */
public class MyShiroRealm extends AuthorizingRealm {

    @Resource(name = "indexService")
    private IndexService indexService;

    /**
     * 获取授权信息
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String userName = (String)principals.getPrimaryPrincipal();

        // 用户权限列表
        Set<String> permsSet = Collections.singleton("test");

        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        authorizationInfo.setStringPermissions(permsSet);

        return authorizationInfo;
    }

    /**
     * 获取认证信息
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;

        String username = token.getUsername();

        SysUser user = null;
        if (username != null  && !"".equals(username)) {
            user = indexService.selectUserInfoByUsername(username);
        }

        if (null == user) {
            // 没找到帐号
            throw new UnknownAccountException();
        }
        if (user.getStatus() == 0) {
            // 用户被停用
            throw new LockedAccountException();
        }

        ByteSource salt = ByteSource.Util.bytes(user.getUsername());

        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(token.getPrincipal(), user.getPassword(),
                 salt, getName());
        return info;
    }


    public static void main(String[] args) throws ParseException {
        String hashAlgorithmName = "MD5";
        String credentials = "123456";
        int hashIterations = 3;
        ByteSource salt = ByteSource.Util.bytes("test");
        Object obj = new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations);
        System.out.println(obj);

    }
}

五、在controller层实现登录认证&退出登录

@RequestMapping(value="/login_login")
@ResponseBody
public String login_login(String username, String password, String isRememberMe) {

    String error = null;
    try {
        username = URLDecoder.decode(username, "UTF-8");
        password = URLDecoder.decode(password, "UTF-8");
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }
    System.out.println(username + password);
    // 先把账号密码传入shiro里面的UsernamePasswordToken对象里面
    UsernamePasswordToken token = new UsernamePasswordToken(username, password);
    // 创建Subject对象
    Subject subject = SecurityUtils.getSubject();

    if ("1".equals(isRememberMe)) {
        token.setRememberMe(true);
    }

    // 调用subject.login()进行登录
    try {
        subject.login(token);

        //SysUser sysUser = (SysUser) subject.getPrincipals();
    } catch (UnknownAccountException e) {
        error = "用户名/密码错误";
    } catch (IncorrectCredentialsException e) {
        error = "用户名/密码错误";
    } catch (ExcessiveAttemptsException e) {
        // TODO: handle exception
        error = "登录失败多次,账户锁定10分钟";
    } catch (AuthenticationException e) {
        // 其他错误,比如锁定,如果想单独处理请单独catch处理
        error = "其他错误:" + e.getMessage();
    }

    if (error != null) {
        // 出错了,返回登录页面

        return error;
    } else {
        // 登录成功
        return "success";
    }
    
    /**
     * 退出登录
     * @return
     */
    @RequestMapping("/logout")
    public ModelAndView logout() {
        ModelAndView mv = new ModelAndView();
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        mv.setViewName("login");
        return mv;
    }
}

shiro使用就是这么简单,原理:下次搞懂了再讲。。。

原文地址:https://www.cnblogs.com/steveshao/p/13555169.html