SpringBoot整合Apache Shiro

 

Subject 用户主体 (把操作交给SecurityManager)
SecurityManager 安全管理器 (关联Realm)
Realm   Shiro连接数据的桥梁

 

引入maven依赖

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

 

配置自定义Realm

UserRealm.java
package com.shiro;

import com.entity.User;
import com.service.UserService;
import org.apache.shiro.SecurityUtils;
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.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.ArrayList;
import java.util.List;

/**
 * 自定义realm
 */
public class UserRealm extends AuthorizingRealm {

    @Autowired
    private UserService userService;


    /**
     * 执行授权逻辑
     *
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

        //给请求进行授权
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

        //获取登录用户信息
        Subject subject = SecurityUtils.getSubject();

        //取出来的user与下方认证方法中new SimpleAuthenticationInfo(user, user.getPassword(), getName());的第一个存入的参数对应
        User user = (User) subject.getPrincipal();


        //这里为了做演示,实际开发中需要从数据库获取该用户的权限
        List permList = new ArrayList();
        permList.add("user:delete");


        //添加请求的授权集合
        info.addStringPermissions(permList);


        return info;
    }


    /**
     * 执行认证逻辑
     *
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {

        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;

        //查询用户名是否存在
        User user = userService.findByUserName(token.getUsername());
        if (user == null) {
            //用户不存在,shiro底层会抛出UnknownAccountException异常
            throw new UnknownAccountException();
        }

        if (!user.getEnable()) {
            throw new LockedAccountException();
        }

        //通过这个进行认证,并返回 实际使用中密码要进行加密  这里放入的第一个参数user和上面授权方法中subject.getPrincipal();这个取到的内容对应
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(user, user.getPassword(), getName());

        // 当验证都通过后,把用户信息放在session里
        Session session = SecurityUtils.getSubject().getSession();
        session.setAttribute("user", user);

        return simpleAuthenticationInfo;
    }
}


shiro配置类
ShiroConfig.java
package com.shiro;

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;


/**
 * shiro配置类
 */
@Configuration
public class ShiroConfig {


    /**
     * 创建shiroFilterFatoryBean
     */
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(){

        ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean();

        //设置安全管理器
        shiroFilterFactoryBean.setSecurityManager(getDefaultWebSecurityManager());

        //添加shiro内置过滤器
        /**
         * shiro内置过滤器,可以实现权限相关的拦截器功能
         * 常用的过滤器
         *      anon:无需认证(登录)可以访问
         *      authc:必须认证才可以访问
         *      user:如果使用rememberMe的功能可以直接访问
         *      perms:该资源必须得到资源权限才可以访问
         *      role:该资源必须得到角色权限才可以访问
         *
         */
        Map<String,String> filterMap=new LinkedHashMap<>();

        filterMap.put("/back/*","authc");

        //放行登录页面和登录提交请求
        filterMap.put("/login","anon");
        filterMap.put("/toLogin","anon");

        /**
         * 授权过滤器,表示用户执行 “/delete” 操作需要有 “user:delete” 的授权
         * 当前授权拦截后,shiro会自动跳转到未授权页面
         */
        filterMap.put("/delete","perms[user:delete]");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);

        //设置登录页面的请求链接
        shiroFilterFactoryBean.setLoginUrl("/toLogin");

        //设置未授权时的跳转链接
        shiroFilterFactoryBean.setUnauthorizedUrl("/toUnauthorizedUrl");

        return shiroFilterFactoryBean;
    }


    /**
     * 创建DefaultWebSecurityManager
     */
    @Bean
    public DefaultWebSecurityManager getDefaultWebSecurityManager(){
        DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();

        //关联realm
        securityManager.setRealm(getRealm());
        return securityManager;
    }

    /**
     * 创建Realm
     */
    @Bean
    public UserRealm getRealm(){
        return new UserRealm();
    }




}

 

配置规则详细说明

// 将需要配置的地址放入map中,规则如下:
/**
anon:例子/admins/**=anon 没有参数,表示可以匿名使用。

authc:例如/admins/user/**=authc表示需要认证(登录)才能使用,没有参数

roles(角色):例子/admins/user/**=roles[admin],参数可以写多个,多个时必须加上引号,
并且参数之间用逗号分割,当有多个参数时,例如admins/user/**=roles["admin,guest"],
每个参数通过才算通过,相当于hasAllRoles()方法。

perms(权限):例子/admins/user/**=perms[user:add:*],参数可以写多个,多个时必须加上引号,
并且参数之间用逗号分割,例如/admins/user/**=perms["user:add:*,user:modify:*"],
当有多个参数时必须每个参数都通过才通过,想当于isPermitedAll()方法。

rest:例子/admins/user/**=rest[user],根据请求的方法,相当于/admins/user/**=perms[user:method] ,
其中method为post,get,delete等。

port:例子/admins/user/**=port[8081],当请求的url的端口不是8081是跳转到
schemal://serverName:8081?queryString,其中schmal是协议http或https等,
serverName是你访问的host,8081是url配置里port的端口,queryString是你访问的url里的?后面的参数。

authcBasic:例如/admins/user/**=authcBasic没有参数表示httpBasic认证

ssl:例子/admins/user/**=ssl没有参数,表示安全的url请求,协议为https

user:例如/admins/user/**=user没有参数表示必须存在用户,当登入操作时不做检查
*/
// 详情参考shiro.web.filter源码

 

 

 

 

控制器类,登录 退出方法

LoginController.java
package com.controller;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class LoginController {


    /**
     * 登录请求方法
     *
     * @param username 用户名
     * @param password 密码
     * @return
     */
    @PostMapping(value = "/login")
    public String loginPost(String username, String password) {

        /**
         * 使用Shiro进行认证操作
         */
        //获取Subject
        Subject subject = SecurityUtils.getSubject();

        //封装用户数据
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);

        //是否记住我操作,这里我默认设置记住我
        token.setRememberMe(true);


        //执行登录方法
        try {
            subject.login(token);

            //登录成功操作

        } catch (UnknownAccountException e) {
            //用户不存在
            e.printStackTrace();


        } catch (IncorrectCredentialsException e) {
            //用户名密码错误
            e.printStackTrace();


        } catch (LockedAccountException e) {
            e.printStackTrace();
            //账号被禁用
        }

        return null;
    }


    /**
     * 登出
     *
     * @return
     */
    @RequestMapping("/logout")
    public String logout() {
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        Session session = subject.getSession();
        //情况session中的用户信息
        session.removeAttribute("user");

        //返回登录页
        return "login";
    }


}

 




posted @ 2020-05-23 18:00  yvioo  阅读(595)  评论(0编辑  收藏  举报