Shiro权限管理
shiro
Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。
角色权限管理
- 新建权限实体类Permission,实现序列化的接口
@Entity
@Table(name = "t_permission")
public class Permission implements Serializable {
private static final long serialVersionUID = 6969178802824371390L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) //自增
private Long id;
private String name;
private String code;
private String description;
public static long getSerialVersionUID() {
return serialVersionUID;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
- 新建角色实体类Role,实现序列化的接口
@Entity
@Table(name = "t_role")
public class Role implements Serializable {
private static final long serialVersionUID = -1513987909228269210L;//序列id
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) //自增
private Long id;
private String name;
private String description;
@ManyToMany(mappedBy = "roles")
private Set<User> users = new HashSet<>(0);
@ManyToMany(fetch = FetchType.EAGER)
private Set<Permission> permissions = new HashSet<>(0);
public static long getSerialVersionUID() {
return serialVersionUID;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Set<User> getUsers() {
return users;
}
public void setUsers(Set<User> users) {
this.users = users;
}
public Set<Permission> getPermissions() {
return permissions;
}
public void setPermissions(Set<Permission> permissions) {
this.permissions = permissions;
}
@Override
public String toString() {
return "Role{" +
"id=" + id +
", name='" + name + '\'' +
", description='" + description + '\'' +
", users=" + users +
", permissions=" + permissions +
'}';
}
}
这里需要添加唯一的一个序列id
File -> Settings -> Editor -> Inspections -> Serialization issues 勾选全部
再在Role类名处Alt+Enter 添加唯一序列,同样在Permission也需要
在Role新增了和User实体的关系,同样在User中也需要新增和Role的实体关系
@ManyToMany(fetch = FetchType.EAGER)
private Set<Role> roles = new HashSet<>(0);
- 添加shiro依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.3.2</version>
</dependency>
- 新建realm包 -> 新建NewsRealm
public class NewRealm extends AuthorizingRealm {
public void setName(String name){setName("nameRealm");}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken upToken = (UsernamePasswordToken)authenticationToken;
String username = upToken.getUsername();
String password = new String(upToken.getPassword());
User user = userService.checkUsers(username,password);
if(user != null){
return new SimpleAuthenticationInfo(user,user.getPassword(),this.getName());
}
return null;
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//获取用户认证信息
User user = (User)principalCollection.getPrimaryPrincipal();
//构造认证数据
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
Set<Role> roles = user.getRoles();
for(Role role:roles){
//添加角色信息
info.addRole(role.getName());
for(Permission permission:role.getPermissions()){
info.addStringPermission(permission.getCode());
}
}
return info;
}
@Autowired
private UserService userService;
}
- 新建Shiro配置文件ShiroConfiguration(在realm文件夹在同一目录)
@Configuration
public class ShiroConfiguration {
//创建realm
@Bean
public NewRealm getRealm(){return new NewRealm();}
//创建安全管理器
@Bean
public SecurityManager securityManager(NewRealm realm){
//使用默认的安全管理器
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(realm);
return securityManager;
}
//配置shiro过滤器工厂
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactory = new ShiroFilterFactoryBean();
shiroFilterFactory.setSecurityManager(securityManager);
//通用配置
shiroFilterFactory.setLoginUrl("/admin");
shiroFilterFactory.setUnauthorizedUrl("/admin");
/**
* key: 请求路径
* value: 过滤器类型
*/
Map<String,String> filterMap = new LinkedHashMap<>();
filterMap.put("/admin/login","anon");
filterMap.put("/admin/**","authc");
shiroFilterFactory.setFilterChainDefinitionMap(filterMap);
return shiroFilterFactory;
}
//开启shiro注解支持
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager);
return advisor;
}
}
- 修改LoginController的login方法
@PostMapping("/login")
public String login(@RequestParam String username , @RequestParam String password,
HttpSession session, RedirectAttributes attributes) {
/**
* 原来的登陆验证方法
User user = userService.checkUsers(username, password);
if (user != null) {
user.setPassword(null);
session.setAttribute("user", user);
return "admin/index";
} else {
attributes.addFlashAttribute("message", "用户名或密码错误");
return "redirect:/admin";
}
*/
//使用注册登陆令牌
try{
//构造登陆令牌
UsernamePasswordToken uptoken = new UsernamePasswordToken(username,password);
//获取subject (主体)
Subject subject = SecurityUtils.getSubject();
//登陆 使用令牌
subject.login(uptoken);
User user = (User) subject.getPrincipal();
session.setAttribute("user",user);
return "admin/index";
} catch (Exception e) {
attributes.addFlashAttribute("message","用户名或密码错误");
return "redirect:/admin";
}
}
-
测试
输入admin/下的路径时自动跳转到登陆界面
-
权限职责分配
不同的用户负责的模块不一样,例如1用户负责新闻模块、2用户负责分类模块…-
在permission数据表中添加职责对应关系
-
在user数据表中添加相应关系
-
在角色和权限中间表中声明对应关系
-
用户和角色关系对应表
修改ShiroConfiguration
添加代码
-
filterMap.put("/admin/types","perms[user_types]");
filterMap.put("/admin/news","perms[user_news]");
filterMap.put("/admin/tags","perms[user_tags]");
便可以实现不同权限的用户只能访问当前权限下的功能模块