springboot 接入shiro

1、建表、建实体类、service、mapper等,目的是查询用户信息和角色信息

查看代码
-- 三张表,二张关系表
create table if not exists sys_permissions
(
	id int auto_increment comment '编号'
		primary key,
	permission varchar(100) null comment '权限编号',
	description varchar(100) null comment '权限描述',
	rid int null comment '此权限关联角色的id',
	available int default 0 null comment '是否锁定',
	constraint idx_sys_permissions_permission
		unique (permission)
);

create table if not exists sys_roles
(
	id int auto_increment comment '角色编号'
		primary key,
	role varchar(100) null comment '角色名称',
	description varchar(100) null comment '角色描述',
	pid int null comment '父节点',
	available int default 0 null comment '是否锁定',
	constraint idx_sys_roles_role
		unique (role)
);

create table if not exists sys_roles_permissions
(
	role_id int null comment '角色编号',
	permission_id int null comment '权限编号'
);

create table if not exists sys_users
(
	id int auto_increment comment '编号'
		primary key,
	username varchar(100) null comment '用户名',
	password varchar(100) null comment '密码',
	salt varchar(100) null comment '盐值',
	role_id varchar(50) null comment '角色列表',
	locked int default 0 null comment '是否锁定',
	constraint idx_sys_users_username
		unique (username)
);

create table if not exists sys_users_roles
(
	user_id int null comment '用户编号',
	role_id int null comment '角色编号'
);

2、pom

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

3、 CustomRealm:自定义Realm用于查询用户的角色和权限信息并保存到权限管理器

import com.pingan.domain.login.Permissions;
import com.pingan.domain.login.Role;
import com.pingan.domain.login.User;
import com.pingan.servcie.LoginService;
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.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ObjectUtils;

public class CustomRealm extends AuthorizingRealm {

    @Autowired
    private LoginService loginService;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //获取登录用户名
        String name = (String) principalCollection.getPrimaryPrincipal();
        //查询用户名称
        User user = loginService.getUserByName(name);
        //添加角色和权限
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();

        //添加角色
        for (Role role : user.getRoleSet()) {
            simpleAuthorizationInfo.addRole(role.getRoleName());

            //添加权限
            for (Permissions permissions : role.getPermissionSet()) {
                simpleAuthorizationInfo.addStringPermission(permissions.getPermissionsName());
            }
        }

        return simpleAuthorizationInfo;
    }
    //认证  返回null 或者SimpleAuthenticationInfo抛异常都算认证失败
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        if (ObjectUtils.isEmpty(authenticationToken.getPrincipal())){
            return null;
        }

        String name = authenticationToken.getPrincipal().toString();
        User user = loginService.getUserByName(name);
        if (user == null) {
            return null;
        } else {
            SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(name, user.getPassword().toString(), getName());
            return simpleAuthenticationInfo;
        }
    }
}

 4、ShiroConfig:shiro的配置类

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.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;

@Configuration
public class ShiroConfig {

    // 授权所用配置
    @Bean
    @ConditionalOnMissingBean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }

    //将自定义的验证方式加入容器
    @Bean
    public CustomRealm customRealm() {
        CustomRealm customRealm = new CustomRealm();
        return customRealm;
    }

    // 设置session过期时间
    @Bean(name = "sessionManager")
    public DefaultWebSessionManager sessionManager() {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        // 设置session过期时间10s
        sessionManager.setGlobalSessionTimeout(10*1000L);
        return sessionManager;
    }

    //权限管理,配置主要是Realm的管理认证
    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
        defaultWebSecurityManager.setRealm(customRealm());
        defaultWebSecurityManager.setSessionManager(sessionManager());
        return defaultWebSecurityManager;
    }


    //Filter工厂,设置对应的过滤条件和跳转条件
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        LinkedHashMap<String, String> map = new LinkedHashMap<>();
        // 不拦截的路径
        // swagger
        map.put("/swagger-ui.html", "anon");
        map.put("/swagger/**", "anon");
        map.put("/swagger-resources/**", "anon");
        map.put("/v2/**", "anon");
        map.put("/webjars/**", "anon");
        map.put("/configuration/**", "anon");
        map.put("/doc.html","anon");

        // 其它 anon 代表不拦截
        map.put("/parent/*", "anon");

        //登出 并清理seesion?登出后需要重新登陆
        map.put("/logout", "logout");
        // 拦截所有路径(除了不拦截的)
        map.put("/**", "authc");
        shiroFilterFactoryBean.setLoginUrl("/testLogin");
        shiroFilterFactoryBean.setSuccessUrl("/index");
        shiroFilterFactoryBean.setUnauthorizedUrl("/error");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);

        return shiroFilterFactoryBean;
    }

    // 使授权注解起作用
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }
    
    // 自定义密码加密解密方式
    // 在 myRealm重写这个方法设置新较验类 CustomCredentialsMatcher
    @Override
    public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
        CustomCredentialsMatcher customCredentialsMatcher = new CustomCredentialsMatcher();
        super.setCredentialsMatcher(customCredentialsMatcher);
    }
}

密码较验类

import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.SimpleCredentialsMatcher;
import org.springframework.util.StringUtils;

// 自定义密码较验方式 写完这个类后要在自定义类MyRealm里重写 setCredentialsMatcher
public class CustomCredentialsMatcher extends SimpleCredentialsMatcher  {
    @Override
    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
        String username = usernamePasswordToken.getUsername();
        String password = String.valueOf(usernamePasswordToken.getPassword());
        String host = usernamePasswordToken.getHost();
        System.out.println("host = " + host);

        if (username.equals("root")) {
            System.out.println("dddd = ----------" );
            return true;
        }
        System.out.println(username+"============");
        System.out.println("password = " + password);
        return false;
//        return super.doCredentialsMatch(token, info);
    }
}

 

5、登陆Controller

@RestController
public class LoginController {

    @Autowired
    private UserMapper userMapper;

   @GetMapping("/login")
    private Object login(@RequestParam("username") String username, @RequestParam("password")String password, HttpServletRequest request) {
        String ipAddress = getIpAddress(request);
    
       // 调用shiro 传入username,password,ip (ip可传可不传)
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username,password,ipAddress);
        try {
            subject.login(usernamePasswordToken);
        } catch (AuthenticationException e) {
            e.printStackTrace();
            return "登陆失败";
        }
    
        return "登陆成功啦啦啦啦";
}

    //通过request取到ip地址
    private static String getIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("X-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
}

 6、在对应用controller方法 或者service方法上加注解

 @RequiresRoles

例如:@RequiresRoles(“aRoleName”);

void someMethod();

如果subject中有aRoleName角色才可以访问方法someMethod。如果没有这个权限则会抛出异常AuthorizationException。 

 

@RequiresPermissions

例如: @RequiresPermissions({“file:read”, “write:aFile.txt”} )
void someMethod();

要求subject中必须同时含有file:read和write:aFile.txt的权限才能执行方法someMethod()。否则抛出异常AuthorizationException。

 

上一篇:jquery之别踩白块游戏的实现


下一篇:基于SpringBoot + Thymeleaf + Layui + Apache Shiro + Redis + Mybatis Plus 的后台管理系统 提供代码生成器