ZengTao
2023-10-30 d06205a8e488c1857ff0c02cf3f59fea720688bb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
package com.example.springboot.security.config;
 
import com.example.springboot.security.JWTRealm;
import com.example.springboot.security.NoSessionFilter;
import com.example.springboot.security.StatelessDefaultSubjectFactory;
import com.example.springboot.security.UserRealm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
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.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
 
import javax.servlet.Filter;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
 
@Configuration
public class ShiroConfig {
 
 
    /**
     * Shiro生命周期处理器
     *
     * @return
     */
    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }
 
    /**
     * 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证
     * DefaultAdvisorAutoProxyCreator的顺序必须在shiroFilterFactoryBean之前,不然SecurityUtils.getSubject().getPrincipal()获取不到参数
     *
     * @return
     */
    @Bean
    @DependsOn({"lifecycleBeanPostProcessor"})
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }
 
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(defaultSecurityManager());
        return authorizationAttributeSourceAdvisor;
    }
 
    @Bean(name = "shiroFilterFactoryBean")
    public ShiroFilterFactoryBean shiroFilterFactoryBean() {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(defaultSecurityManager());
 
        // 过滤规则
        Map<String, String> linkedHashMap = new LinkedHashMap<>();
        // 无状态登录情况下关闭了shiro中的session,导致所有需要加上authc接口请求时候都会报错,
        // 所以使用@RequiresRoles,@RequiresPermissions注解,aop方式实现接口的权限校验
 
        /* 添加shiro的内置过滤器,自定义url规则
         * Shiro自带拦截器配置规则
         * 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里的?后面的参数
         * perms:比如/admins/user/**=perms[user:add:*],perms参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,比如/admins/user/**=perms["user:add:*,user:modify:*"],当有多个参数时必须每个参数都通过才通过,想当于isPermitedAll()方法
         * roles:比如/admins/user/**=roles[admin],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,当有多个参数时,比如/admins/user/**=roles["admin,guest"],每个参数通过才算通过,相当于hasAllRoles()方法。//要实现or的效果看http://zgzty.blog.163.com/blog/static/83831226201302983358670/
         * anon:比如/admins/**=anon 没有参数,表示可以匿名使用
         * authc:比如/admins/user/**=authc表示需要认证才能使用,没有参数
         * authcBasic:比如/admins/user/**=authcBasic没有参数表示httpBasic认证
         * ssl:比如/admins/user/**=ssl没有参数,表示安全的url请求,协议为https
         * user:比如/admins/user/**=user没有参数表示必须存在用户,当登入操作时不做检查
         * 详情见文档 http://shiro.apache.org/web.html#urls-
         * */
        // 用户权限
//        linkedHashMap.put("/api/user/selectPage", "perms[user:select]");
//        linkedHashMap.put("/api/user/selectById", "perms[user:select]");
//        linkedHashMap.put("/api/user/updateById", "perms[user:update]");
//        linkedHashMap.put("/api/user/removeByIds", "perms[user:delete]");
//        // 商品权限
//        linkedHashMap.put("/api/product/deleteBatchIds", "perms[product:delete]");
//        linkedHashMap.put("/api/product/updateById", "perms[product:update]");
//        linkedHashMap.put("/api/product/insert", "perms[product:add]");
//
//        // 角色权限
//        linkedHashMap.put("/api/role/saveOrUpdate", "perms[role:add,role:update]");
//        linkedHashMap.put("/api/role/removeByIds", "perms[role:delete]");
//        linkedHashMap.put("/api/role/getById", "perms[role:select]");
//        linkedHashMap.put("/api/role/selectPage", "perms[role:select]");
//
//        // 菜单权限
//        linkedHashMap.put("/api/menuList/removeByIds", "perms[menuList:delete]");
//        linkedHashMap.put("/api/menuList/saveOrUpdate", "perms[menuList:add,menuList:update]");
//
//        // 订单权限
//        linkedHashMap.put("/api/order/deleteBatchIds", "perms[order:delete]");
//        linkedHashMap.put("/api/order/updateById", "perms[order:update]");
//
//        // 授权的权限
//        linkedHashMap.put("/api/rolePermission/saveOrUpdate", "perms[rolePermission:add]");
//        linkedHashMap.put("/api/rolePermission/removeByIds", "perms[rolePermission:delete]");
 
        // 自定义过滤器
        HashMap<String, Filter> filterHashMap = new HashMap<>();
        filterHashMap.put("jwt", new NoSessionFilter());
        shiroFilterFactoryBean.setFilters(filterHashMap);
        // 登录之后才可以请求的接口
        linkedHashMap.put("/api/**", "jwt");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(linkedHashMap);
        return shiroFilterFactoryBean;
    }
 
    @Bean
    public DefaultWebSecurityManager defaultSecurityManager() {
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
        defaultWebSecurityManager.setRealms(Arrays.asList(userRealm(), jwtRealm()));
        // 禁用shiro中的session
        DefaultSubjectDAO defaultSubjectDAO = new DefaultSubjectDAO();
        DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
        defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
        defaultSubjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
        defaultWebSecurityManager.setSubjectDAO(defaultSubjectDAO);
        defaultWebSecurityManager.setSubjectFactory(subjectFactory());
        return defaultWebSecurityManager;
    }
 
    /**
     * 登录的认证和授权
     *
     * @return
     */
    @Bean
    public UserRealm userRealm() {
        UserRealm userRealm = new UserRealm();
        userRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return userRealm;
    }
 
    /**
     * token的认证和授权
     *
     * @return
     */
    @Bean
    public JWTRealm jwtRealm() {
        return new JWTRealm();
    }
 
    @Bean
    public StatelessDefaultSubjectFactory subjectFactory() {
        return new StatelessDefaultSubjectFactory();
    }
 
    /*
     * 凭证匹配器 由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了
     */
    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName("MD5");// 散列算法:这里使用MD5算法;
        hashedCredentialsMatcher.setHashIterations(1024);// 散列的次数,比如散列两次,相当于MD5(MD5(""));
        return hashedCredentialsMatcher;
    }
 
    @Bean
    public CookieRememberMeManager cookieRememberMeManager() {
        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
        SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
        simpleCookie.setMaxAge(259200000);
        cookieRememberMeManager.setCookie(simpleCookie);
        cookieRememberMeManager.setCipherKey(Base64.decode("6ZmI6I2j5Y+R5aSn5ZOlAA=="));
        return cookieRememberMeManager;
    }
}