SpringBoot结合shiro

参考资料

项目地址

Realm

实现类继承AuthorizingRealm接口,自定义Realm接口(用户数据和Shiro数据交互的桥梁。比如需要用户身份认证、权限认证。都是需要通过Realm来读取数据)

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
public class CustomRealm extends AuthorizingRealm {

@Autowired
private ShiroService shiroService;

/**
* 授权处理 权限相关
* 注解@RequiresPermissions()用来判断是否有权限执行
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
// 从doGetAuthenticationInfo方法中返回的SimpleAuthenticationInfo对象中去取
Role primaryPrincipal = (Role) principalCollection.getPrimaryPrincipal();
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
Set<String> stringSet = new HashSet<>();
stringSet.addAll(primaryPrincipal.getPermissionList());
info.setStringPermissions(stringSet);
return info;
}

/**
* 登录认证
* 身份认证
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//获取基于用户名和密码的令牌
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
//获取登录用
String userName = token.getUsername();
//从数据库中获取对应用户名对应的user
Role role = shiroService.login(userName, userPwd);
//异常处理
if (Utils.objectIsEmpty(role)) throw new AccountException();
//返回验证结果 将role对象放入SimpleAuthenticationInfo中
return new SimpleAuthenticationInfo(role, role.getPassword(), getName());
}
}

Controller层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@RequestMapping(value = "/login", method = RequestMethod.POST)
public String login(@RequestParam("username") String username, @RequestParam("password") String password,@RequestParam("rememberMe") boolean rememberMe) {
// 从SecurityUtils里边创建一个 subject代表当前正在执行操作的用户
Subject subject = SecurityUtils.getSubject();
// 在认证提交前准备 token(令牌)
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
token.setRememberMe(rememberMe);
// 验证角色和权限,此处执行自定义的Realm接口方法
subject.login(token);
if (subject.isAuthenticated()) {
return "登录成功";
} else {
token.clear();
return "登录失败";
}
}

ShiroConfig

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
@Configuration
public class ShiroConfig {

@Bean(name = "shiroFilter")
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
shiroFilterFactoryBean.setLoginUrl("/login");
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
// anon:所有url都都可以匿名访问
filterChainDefinitionMap.put("/login", "anon");
filterChainDefinitionMap.put("/", "anon");
// authc:所有url都必须认证通过才可以访问
filterChainDefinitionMap.put("/admin/**", "authc");
filterChainDefinitionMap.put("/user/**", "authc");
//主要这行代码必须放在所有权限设置的最后,不然会导致所有 url 都被拦截 剩余的都需要认证
filterChainDefinitionMap.put("/**", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;

}

/**
* cookie对象;
* @return
*/
public SimpleCookie rememberMeCookie(){
//这个参数是cookie的名称,对应前端的checkbox的name = rememberMe
SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
//cookie生效时间30天,单位秒;
simpleCookie.setMaxAge(2592000);
return simpleCookie;
}

/**
* cookie管理对象;记住我功能
* @return
*/
public CookieRememberMeManager rememberMeManager(){
CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
cookieRememberMeManager.setCookie(rememberMeCookie());
// cookieRememberMeManager.setCipherKey用来设置加密的Key,参数类型byte[],字节数组长度要求16
cookieRememberMeManager.setCipherKey("ZHANGXIAOHEI_CAT".getBytes());
return cookieRememberMeManager;
}

@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(customRealm());
// 设置rememberMe
securityManager.setRememberMeManager(rememberMeManager());
return securityManager ;
}

@Bean
public CustomRealm customRealm() {
CustomRealm customRealm = new CustomRealm();
return customRealm;
}

@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}

/**
* *
* 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证
* *
* 配置以下两个bean(DefaultAdvisorAutoProxyCreator(可选)和AuthorizationAttributeSourceAdvisor)即可实现此功能
* * @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(securityManager());
return authorizationAttributeSourceAdvisor;
}
}

全局异常处理

1
2
3
4
5
6
7
8
9
10
11
12
13
@ControllerAdvice
public class NoPermissionException {
@ResponseBody
@ExceptionHandler(UnauthorizedException.class)
public String handleShiroException(Exception ex) {
return "您没有该权限";
}
@ResponseBody
@ExceptionHandler(AuthorizationException.class)
public String AuthorizationException(Exception ex) {
return "权限认证失败";
}
}
赏个🍗吧
0%