springboot篇】十五. springboot整合shiro多Realm控制

springboot整合shiro多Realm控制

中国加油,武汉加油!

篇幅较长,配合右边目录观看

项目准备
  1. 创建springboot项目nz1904-springboot-08-manyroles
  2. 导入spring的web包,lombox,thymeleaf包及shiro包
    <!-- spring跟shiro整合依赖-->
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-spring</artifactId>
        <version>1.3.2</version>
    </dependency>
    

1. 案例

1.1 自定义类增强UsernamePasswordToken

package com.wpj.token;

import org.apache.shiro.authc.UsernamePasswordToken;

public class CustomToken extends UsernamePasswordToken {

    // 定义登录类型,为了在后面的时候中校验使用那个realm
    private String loginType;


    public CustomToken(String userName, String password, String loginType){
        super(userName,password);
        this.loginType = loginType;
    }

    public String getLoginType() {
        return loginType;
    }

    public void setLoginType(String loginType) {
        this.loginType = loginType;
    }

}

1.2 自定义ModularRealmAuthenticator来选择使用哪个realm来进行认证

package com.wpj.authticator;

import com.wpj.token.CustomToken;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
import org.apache.shiro.realm.Realm;

import java.util.ArrayList;
import java.util.Collection;

/**
 * 在这里选择使用哪个realm来进行认证
 */
public class CustomModularRealmAuthenticator extends ModularRealmAuthenticator {

    /**
     * 通过传入数据类型来选择使用哪个realm
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException {
        // 做realm的校验
        assertRealmsConfigured();
        // 获取从前端传过来的token
        CustomToken customToken = (CustomToken) authenticationToken;
        // 获取登录类型
        String loginType = customToken.getLoginType();
        // 获取所有token
        Collection<Realm> realms = getRealms();
        // 登录类型对应多有realm全部获取到
        Collection<Realm> typeRealms = new ArrayList<Realm>();
        for (Realm realm: realms) {
            // 类型对比
            if (realm.getName().contains(loginType)) {
                typeRealms.add(realm);
            }
        }

        if(typeRealms.size() == 1) {
            return doSingleRealmAuthentication(typeRealms.iterator().next(), customToken);
        } else {
            return doMultiRealmAuthentication(typeRealms,customToken);
        }

    }
}

1.3 定义一个登录类型的枚举

package com.wpj.type;

public enum LoginType {

    USER("User"), ADMIN("Admin");

    private String type;

    private LoginType(String type) {
        this.type = type;
    }

    @Override
    public String toString() {
        return this.type.toString();
    }
}

1.5 application.properties配置

# 配置模板引擎
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.mode=HTML5
spring.thymeleaf.encoding=utf-8
spring.thymeleaf.cache=false

1.6 新建登录页面和各自登录成功的页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <base th:href="${#request.getContextPath()+'/'}">
</head>
<body>
    User登录
    <form action="/userLogin" method="post">
        姓名: <input type="text" name="name" /><br />
        密码: <input type="text" name="pwd" /><br />
        <input type="submit" value="登录">
    </form>
    <br />
    Admin登录
    <form action="/adminLogin" method="post">
        姓名: <input type="text" name="name" /><br />
        密码: <input type="text" name="pwd" /><br />
        <input type="submit" value="登录">
    </form>
</body>
</html>
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <base th:href="${#request.getContextPath()+'/'}">
</head>
<body>
    this is user_index page
</body>
</html>
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <base th:href="${#request.getContextPath()+'/'}">
</head>
<body>
    this is admin_index page.
</body>
</html>

在这里插入图片描述

1.7 定义一个ShiroConfig

package com.wpj.config;

import com.wpj.authticator.CustomModularRealmAuthenticator;
import com.wpj.realm.AdminRealm;
import com.wpj.realm.UserRealm;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.context.annotation.Bean;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@SpringBootConfiguration
public class ShiroConfig {
    // 拦截过滤器
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        // 认证失败跳转页面
        shiroFilterFactoryBean.setLoginUrl("/toLogin");
        // 权限不够跳转页面
        shiroFilterFactoryBean.setUnauthorizedUrl("/toUnAuthorization");

        Map<String, String> map = new LinkedHashMap<String, String>();
        map.put("/toLogin", "anon");
        map.put("/userLogin", "anon");
        map.put("/adminLogin", "anon");
        map.put("/**", "authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        //设置安全管理器
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        return shiroFilterFactoryBean;
    }
    // 配置安全管理器
    @Bean
    public DefaultWebSecurityManager securityManager(){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 设置校验的Realm对象
        securityManager.setAuthenticator(authenticator());
        List<Realm> realms = new ArrayList<Realm>();
        realms.add(userRealm());
        realms.add(adminRealm());

        securityManager.setRealms(realms);
        return securityManager;
    }

    @Bean
    public UserRealm userRealm(){
        UserRealm userRealm = new UserRealm();
        return userRealm;
    }
    @Bean
    public AdminRealm adminRealm(){
        AdminRealm adminRealm = new AdminRealm();
        return adminRealm;
    }
    // 认证器
    @Bean
    public CustomModularRealmAuthenticator authenticator(){
        CustomModularRealmAuthenticator authenticator = new CustomModularRealmAuthenticator();
        return authenticator;
    }
}

1.8 定义User类和Admin类

package com.wpj.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {

    private static final long serialVersionUID = 8434196542261610760L;
    
    private Integer id;
    private String name;
    private String pwd;
    
}
package com.wpj.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Admin implements Serializable {


    private static final long serialVersionUID = -7243842037245054988L;
    private Integer id;
    private String name;
    private String pwd;

}

1.9 定义UserController和AdminController和跳转到登录页面的Controller

package com.wpj.controller;

import com.wpj.pojo.User;
import com.wpj.token.CustomToken;
import com.wpj.type.LoginType;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class UserController {

    private final String LOGIN_TYPE = LoginType.USER.toString();

    private Logger logger = LoggerFactory.getLogger(UserController.class);
    /**
     * 用户登录的方法
     * @return
     */
    @RequestMapping("/userLogin")
    public String login(User user){

        // 封装请求对象
        CustomToken customToken = new CustomToken(user.getName(),user.getPwd(), LOGIN_TYPE);
        // 获取登录主体
        Subject subject = SecurityUtils.getSubject();
        // 登录
        try {
            subject.login(customToken);
            if(subject.isAuthenticated()){
                // 认证成功
                return "user_index";
            }
        } catch (UnknownAccountException e) {
            logger.error("未知账户");
        } catch (IncorrectCredentialsException e) {
            logger.error("密码错误");
        } catch (Exception e) {
            logger.error("其他错误");
        }
        return "login";

    }

}
package com.wpj.controller;

import com.wpj.pojo.Admin;
import com.wpj.pojo.User;
import com.wpj.token.CustomToken;
import com.wpj.type.LoginType;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class AdminController {

    private final String LOGIN_TYPE = LoginType.ADMIN.toString();

    private Logger logger = LoggerFactory.getLogger(AdminController.class);
    /**
     * 管理员登录的方法
     * @return
     */
    @RequestMapping("/adminLogin")
    public String login(Admin admin){

        // 封装请求对象
        CustomToken customToken = new CustomToken(admin.getName(),admin.getPwd(), LOGIN_TYPE);
        // 获取登录主体
        Subject subject = SecurityUtils.getSubject();
        // 登录
        try {
            subject.login(customToken);
            if(subject.isAuthenticated()){
                // 认证成功
                return "admin_index";
            }
        } catch (UnknownAccountException e) {
            logger.error("未知账户");
        } catch (IncorrectCredentialsException e) {
            logger.error("密码错误");
        } catch (Exception e) {
            logger.error("其他错误");
        }
        return "login";

    }

}
package com.wpj.controller;

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

@Controller
public class IndexController {

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

}

1.10 定义2个Realm

package com.wpj.realm;

import com.wpj.controller.UserController;
import com.wpj.pojo.User;
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.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class UserRealm extends AuthorizingRealm {

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

    @Override
    public String getName() {
        return "UserRealm";
    }
    // 认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        // 获取用户名
        String name = (String) authenticationToken.getPrincipal();
        // 查询数据库
        // 模拟。。。
        //
        if (!(name.equals("jiekami"))) {
            return null;
        }
        logger.info("这里是User认证");
        User user = new User(1,"jiekami","123");
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(user.getName(), user.getPwd(), getName());

        return simpleAuthenticationInfo;
    }
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }

}
package com.wpj.realm;

import com.wpj.pojo.Admin;
import com.wpj.pojo.User;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class AdminRealm extends AuthorizingRealm {
    
    private Logger logger = LoggerFactory.getLogger(AdminRealm.class);

    @Override
    public String getName() {
        return "AdminRealm";
    }
    // 认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        // 获取用户名
        String name = (String) authenticationToken.getPrincipal();
        // 查询数据库
        // 模拟。。。
        // 
        if (!(name.equals("wpj"))) {
            return null;
        }
        // 
        logger.info("这里是Admin认证");
        Admin admin = new Admin(1,"wpj","123");
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(admin.getName(), admin.getPwd(), getName());

        return simpleAuthenticationInfo;
    }
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }
    
}

1.11 启动主启动类

package com.wpj;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ShiroManyrolesApplication {

    public static void main(String[] args) {
        SpringApplication.run(ShiroManyrolesApplication.class, args);
    }

}

1.12 测试

localhost:8080
在这里插入图片描述
输入各自Realm模拟的数据即可跳转到各自的页面

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值