Shiro & Spring Security

The actual development:

A, shiro already meet the basic safety requirements, simple to use, need role and permission to inject the database table to achieve .

(1) Related notes:

@RequiresRoles("xxx")        //角色控制
@RequiresPermissions("xxx")     //功能权限控制

(2) Configuration class ShiroConfig template:

package com.kevin.springbootkevin1.config;

import com.kevin.springbootkevin1.realm.UserRealm;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator;
import org.apache.shiro.session.mgt.eis.MemorySessionDAO;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
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.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;


@Configuration
public class ShiroConfig {

    /**
     * ShiroFilterFactoryBean 处理拦截资源文件问题。
     * 注意:单独一个ShiroFilterFactoryBean配置是或报错的,以为在
     * 初始化ShiroFilterFactoryBean的时候需要注入:SecurityManager
     * Filter Chain定义说明 1、一个URL可以配置多个Filter,使用逗号分隔 2、当设置多个过滤器时,全部验证通过,才视为通过
     * 3、部分过滤器可指定参数,如perms,roles
     */
    @Bean
    public ShiroFilterFactoryBean shirFilter(org.apache.shiro.mgt.SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();

        // 必须设置 SecurityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        // 拦截器.
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();

        //配置静态资源允许访问
        filterChainDefinitionMap.put("/user/login","anon");
        filterChainDefinitionMap.put("/user/loginAction","anon");

        //filterChainDefinitionMap.put("/css/**","anon");
        //filterChainDefinitionMap.put("/index","anon");

        // <!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
        filterChainDefinitionMap.put("/**", "authc");

        // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
        shiroFilterFactoryBean.setLoginUrl("/user/login");

        // 未授权界面;
        shiroFilterFactoryBean.setUnauthorizedUrl("/403");
        Map<String, Filter> filters=new HashMap<String,Filter>();
        shiroFilterFactoryBean.setFilters(filters);
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

    @Bean
    public EhCacheManager getEhCacheManager() {
        EhCacheManager em = new EhCacheManager();
        em.setCacheManagerConfigFile("classpath:ehcache-shiro.xml");
        return em;
    }
    // 开启Controller中的shiro注解
    @Bean
    public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator daap = new DefaultAdvisorAutoProxyCreator();
        daap.setProxyTargetClass(true);
        return daap;
    }
    /**
     * 配置org.apache.shiro.web.session.mgt.DefaultWebSessionManager
     * @return
     */
    @Bean
    public DefaultWebSessionManager getDefaultWebSessionManager(){
        DefaultWebSessionManager defaultWebSessionManager=new DefaultWebSessionManager();
        defaultWebSessionManager.setSessionDAO(getMemorySessionDAO());
        defaultWebSessionManager.setGlobalSessionTimeout(4200000);
        defaultWebSessionManager.setSessionValidationSchedulerEnabled(true);
        defaultWebSessionManager.setSessionIdCookieEnabled(true);
        defaultWebSessionManager.setSessionIdCookie(getSimpleCookie());
        return defaultWebSessionManager;
    }
    /**
     * 配置org.apache.shiro.session.mgt.eis.MemorySessionDAO
     * @return
     */
    @Bean
    public MemorySessionDAO getMemorySessionDAO(){
        MemorySessionDAO memorySessionDAO=new MemorySessionDAO();
        memorySessionDAO.setSessionIdGenerator(javaUuidSessionIdGenerator());
        return memorySessionDAO;
    }
    @Bean
    public JavaUuidSessionIdGenerator javaUuidSessionIdGenerator(){
        return new JavaUuidSessionIdGenerator();
    }
    /**
     * session自定义cookie名
     * @return
     */
    @Bean
    public SimpleCookie getSimpleCookie(){
        SimpleCookie simpleCookie=new SimpleCookie();
        simpleCookie.setName("security.session.id");
        simpleCookie.setPath("/");
        return simpleCookie;
    }
    @Bean
    public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor(){
        return new LifecycleBeanPostProcessor();
    }
    @Bean(name = "securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(UserRealm userRealm) {
        DefaultWebSecurityManager dwsm = new DefaultWebSecurityManager();
        dwsm.setRealm(userRealm);
        //  <!-- 用户授权/认证信息Cache, 采用EhCache 缓存 -->
        dwsm.setCacheManager(getEhCacheManager());
        dwsm.setSessionManager(getDefaultWebSessionManager());
        return dwsm;
    }
    @Bean
    public UserRealm userRealm(EhCacheManager cacheManager) {
        UserRealm userRealm = new UserRealm();
        userRealm.setCacheManager(cacheManager);
        return userRealm;
    }
    /**
     * 开启shrio注解支持
     * @param userRealm
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(UserRealm userRealm){
        AuthorizationAttributeSourceAdvisor aasa=new AuthorizationAttributeSourceAdvisor();
        aasa.setSecurityManager(getDefaultWebSecurityManager(userRealm));
        return aasa;
    }

}

(. 3) The realm layer two important methods:

AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pc):控制角色权限
AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken at) throws AuthenticationException:控制登录

Note:

POM introduced:

<!--Shiro安全-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-ehcache</artifactId>
            <version>1.4.0</version>
        </dependency>

Instructions:

1. Create a database user, role, permission table, corresponding to the user table, table roles, permissions table.

2. Configuration ShiroConfig, as shown above item (2),

Description:

The purpose of this code: add an access request (these requests can not be blocked).

According to another study notes, access to information.

3. Write realm layer

ex:

package com.kevin.springbootkevin1.realm;
import com.kevin.springbootkevin1.bean.User;
import com.kevin.springbootkevin1.mapper.PermissionMapper;
import com.kevin.springbootkevin1.mapper.RoleMapper;
import com.kevin.springbootkevin1.service.IUserService;
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.crypto.hash.Md5Hash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
/**
 * <p>
 *  用户权限类-持久层
 * </p>
 *
 * @author Jia Xin
 * @since 2020-02-11
 */
public class UserRealm extends AuthorizingRealm {

    @Autowired
    private IUserService userService;

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private PermissionMapper permissionMapper;

    //控制角色权限
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pc) {
        //获取登录用户名
        String username = (String)pc.getPrimaryPrincipal();
        //定义一个权限管理器
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info = userService.addRolePermissions(info,username);
        System.out.println("username:"+username+"," +
                "角色和权限信息:" + info);
        return info;
    }

    //控制登录
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken at) throws AuthenticationException {
        AuthenticationInfo info;
        //token携带的主键username
        String username = (String)at.getPrincipal();
        //第一步拦截-如果前端传来的为空
        if(username == null) {
            return null;
        }
        //通过用户名查询得到user实体
        User user = userService.selectUserByUsername(username);
        if(user != null){       //username.equals(user.getUsername())
            String  md5Hash = new Md5Hash(user.getPassword() , "123").toString();
            info = new SimpleAuthenticationInfo(username, md5Hash, getName());
            return info;
        } else {
            //用户名不存在
            return null;
        }
    }
}

Note: selectUserByUsername function written in the service layer.

4. Writing Layer Controller:

Login request: In order to verify, with the md5 hashed.

subject.login (token); shiro security verification.

If it does, then: authentication is unsuccessful; on the contrary, is successful.

//登录验证
    @GetMapping(value = "/loginAction")
    //@RequestBody Map<String, Object> user
    public String loginAction(String username ,String password) {
//        String username = user.get("username").toString();
//        String password = user.get("password").toString();
        //添加用户认证信息
        Subject subject = SecurityUtils.getSubject();
        //用哈希对密码加密
        String md5Hash = new Md5Hash(password, "123").toString();
        //AuthenticationToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword());
        UsernamePasswordToken token = new UsernamePasswordToken(username, md5Hash);
        //System.out.println("subject.isPermitted() => " + subject.isPermitted("sys:delete"));
        try {
            //登录成功
            subject.login(token);
            return "LoginS";
        } catch (Exception e) {
            //登录失败
            return "LoginF";
        }
    }

The simulation data:

user table

role Table

permission表

zhangsan is admin role, roleid = 1, no rights.

lisi is a teacher role, roleid = 2, there is sys: add sys: edit sys: delete permissions.

6. annotated:

The first demonstration of a role in control here.

7. Verify:

A. First lisi Online:

He is a teacher role, no authority.

Getuser initiate the request, abnormal, shiro intercept control, and to be expected.

And springboot console console record:

2020-02-18 00:15:27.312  WARN 11764 --- [nio-8088-exec-6] .m.m.a.ExceptionHandlerExceptionResolver : Resolved [org.apache.shiro.authz.UnauthorizedException: Subject does not have role [admin]]

B. Then zhangsan Online:

He is the admin role, three rights.

Getuser initiated request to get the results, was not blocked and to be expected.

8. demonstrate this.

Two, Spring Security features include shiro can be completed with good support for Spring applications, capable of security functional requirements needed for large-scale software.

Learning materials: the Spring explain the Boot Security

Published 71 original articles · won praise 22 · views 6021

Guess you like

Origin blog.csdn.net/Kevin__Coder/article/details/104268151