写点什么

SpringBoot 整合 Shiro(完整版),java 学习网站

作者:Java高工P7
  • 2021 年 11 月 10 日
  • 本文字数:6186 字

    阅读完需:约 20 分钟

<dependencies>


<dependency>


<groupId>org.springframework.boot</groupId>


<artifactId>spring-boot-starter-data-jpa</artifactId>


</dependency>


<dependency>


<groupId>org.springframework.boot</groupId>


<artifactId>spring-boot-starter-thymeleaf</artifactId>


</dependency>


<dependency>


<groupId>org.springframework.boot</groupId>


<artifactId>spring-boot-starter-web</artifactId>


</dependency>


<dependency>


<groupId>mysql</groupId>


<artifactId>mysql-connector-java</artifactId>


<scope>runtime</scope>


</dependency>


<dependency>


<groupId>org.apache.shiro</groupId>


<artifactId>shiro-spring</artifactId>


<version>1.4.0</version>


</dependency>


<dependency>


<groupId>org.springframework.boot</groupId>


<artifactId>spring-boot-starter-test</artifactId>


<scope>test</scope>


<exclusions>


<exclusion>


<groupId>org.junit.vintage</groupId>


<artifactId>junit-vintage-engine</artifactId>


</exclusion>


</exclusions>


</dependency>


</dependencies>


<build>


<plugins>


<plugin>


<groupId>org.springframework.boot</groupId>


<artifactId>spring-boot-maven-plugin</artifactId>


</plugin>


</plugins>


</build>


</project>

2、项目结构

3、配置链接数据库属性

spring.datasource.url=jdbc:mysql://localhost:3306/shiro?serverTimezone=GMT%2B8


spring.datasource.username=root


spring.datasource.password=root


spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver


spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect


spring.jpa.show-sql=true


spring.jpa.hibernate.ddl-auto=update


spring.jpa.hibernate.use-new-id-generator-mappings=false


spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true


server.port=80


server.servlet.context-path=/shiro


编写代码



1、编写实体类

菜单表实体类 TbMenu,Spring-Data-Jpa 可以根据实体类去数据库新建或更新对应的表结构,详情可以访问Spring-Data-Jpa入门


import com.fasterxml.jackson.annotation.JsonIgnore;


import org.springframework.data.annotation.CreatedBy;


import javax.persistence.*;


import java.util.ArrayList;


import java.util.List;


/**


  • 菜单表

  • @author


*/


@Entity


public class TbMenu {


private Integer id;


private String name;


private String url;


private Integer idx;


@JsonIgnore


private TbMenu parent;


@JsonIgnore


private List<TbMenu> children = new ArrayList<>();


@Id


@GeneratedValue


public Integer getId() {


return id;


}


public void setId(Integer id) {


this.id = id;


}


@Column(unique = true)


public String getName() {


return name;


}


public void setName(String name) {


this.name = name;


}


public String getUrl() {


return url;


}


public void setUrl(String url) {


this.url = url;


}


public Integer getIdx() {


return idx;


}


public void setIdx(Integer idx) {


this.idx = idx;


}


@ManyToOne


@CreatedBy


public TbMenu getParent() {


return parent;


}


public void setParent(TbMenu parent) {


this.parent = parent;


}


@OneToMany(cascade = CascadeType.ALL, mappedBy = "parent")


@OrderBy(value = "idx")


public List<TbMenu> getChildren() {


return children;


}


public void setChildren(List<TbMenu> children) {


this.children = children;


}


}


角色及权限表 SysRole,parent 为 null 时为角色,不为 null 时为权限。


import com.fasterxml.jackson.annotation.JsonIgnore;


import org.springframework.data.annotation.CreatedBy;


import javax.persistence.*;


import java.util.ArrayList;


import java.util.List;


@Entity


/***


  • 角色及角色对应的菜单权限

  • @author


*parent 为 null 时为角色,不为 null 时为权限


*/


public class SysRole {


private Integer id;


private String name; //名称


@JsonIgnore


private SysRole parent;


private Integer idx; //排序


@JsonIgnore


private List<SysRole> children = new ArrayList<>();


@Id


@GeneratedValue


public Integer getId() {


return id;


}


public void setId(Integer id) {


this.id = id;


}


@Column(length = 20)


public String getName() {


return name;


}


public void setName(String name) {


this.name = name;


}


@ManyToOne


@CreatedBy


public SysRole getParent() {


return parent;


}


public void setParent(SysRole parent) {


this.parent = parent;


}


@OneToMany(cascade = CascadeType.ALL, mappedBy = "parent")


public List<SysRole> getChildren() {


return children;


}


public void setChildren(List<SysRole> children) {


this.children = children;


}


public Integer getIdx() {


return idx;


}


public void setIdx(Integer idx) {


this.idx = idx;


}


}


最后实现的就是用户管理了,只需要对添加的用户分配对应的角色就可以了,用户登录时,显示角色对应的权限。


import com.fasterxml.jackson.annotation.JsonIgnore;


import javax.persistence.*;


import java.util.ArrayList;


import java.util.List;


/**


  • 用户表


*/


@Entity


public class SysUser {


private Integer id;


private String username; //账号


private String password; //密码


private String name; //姓名


@JsonIgnore


private List<SysRole> roles = new ArrayList<>(); //角色


@Id


@GeneratedValue


public Integer getId() {


return id;


}


public void setId(Integer id) {


this.id = id;


}


@Column(length = 20, unique = true)


public String getUsername() {


return username;


}


public void setUsername(String username) {


this.username = username;


}


@Column(length = 100)


public String getPassword() {


return password;


}


public void setPassword(String password) {


this.password = password;


}


@Column(length = 20)


public String getName() {


return name;


}


public void setName(String name) {


this.name = name;


}


@ManyToMany(cascade = CascadeType.REFRESH, fetch = FetchType.EAGER)


@JoinTable(name = "sys_user_role", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))


public List<SysRole> getRoles() {


return roles;


}


public void setRoles(List<SysRole> roles) {


this.roles = roles;


}


}

2、Shiro 配置类

Shiro 配置类 ShiroConfig。


import org.apache.shiro.authc.credential.HashedCredentialsMatcher;


import org.apache.shiro.spring.web.ShiroFilterFactoryBean;


import org.apache.shiro.web.mgt.DefaultWebSecurityManager;


import org.springframework.beans.factory.annotation.Qualifier;


import org.springframework.context.annotation.Bean;


import org.springframework.context.annotation.Configuration;


import java.util.LinkedHashMap;


import java.util.Map;


/**


  • @description Shiro 配置类


*/


@Configuration


public class ShiroConfig {


@Bean("hashedCredentialsMatcher")


public HashedCredentialsMatcher hashedCredentialsMatcher() {


HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();


//指定加密方式为 MD5


credentialsMatcher.setHashAlgorithmName("MD5");


//加密次数


credentialsMatcher.setHashIterations(1024);


credentialsMatcher.setStoredCredentialsHexEncoded(true);


return credentialsMatcher;


}


@Bean("userRealm")


public UserRealm userRealm(@Qualifier("hashedCredentialsMatcher") HashedCredentialsMatcher matcher) {


UserRealm userRealm = new UserRealm();


userRealm.setCredentialsMatcher(matcher);


return userRealm;


}


@Bean


public ShiroFilterFactoryBean shirFilter(@Qualifier("securityManager")DefaultWebSecurityManager securityManager) {


ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();


// 设置 SecurityManager,安全管理器


bean.setSecurityManager(securityManager);


// 设置登录跳转页面


bean.setLoginUrl("/index");


// 设置未授权提示页面(没有权限访问后的页面)


bean.setUnauthorizedUrl("/unAuth");


/**


  • Shiro 内置过滤器,可以实现拦截器相关的拦截器

  • 常用的过滤器:


**/


Map<String, String> filterMap = new LinkedHashMap<>();


filterMap.put("/login","anon");


filterMap.put("/user","authc");


filterMap.put("/system","perms[system]");


filterMap.put("/static/**","anon");


filterMap.put("/**","authc");


filterMap.put("/logout", "logout");


bean.setFilterChainDefinitionMap(filterMap);


return bean;


}


/**


  • 注入 securityManager


*/


@Bean(name="securityManager")


public DefaultWebSecurityManager getDefaultWebSecurityManager(HashedCredentialsMatcher hashedCredentialsMatcher) {


DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();


// 关联 realm.


securityManager.setRealm(userRealm(hashedCredentialsMatcher));


return securityManager;


}


}


自定义 Realm 用于查询用户的角色和权限信息并保存到权限管理器中。代码如下:


import com.mcy.springbootshiro.entity.SysRole;


import com.mcy.springbootshiro.entity.SysUser;


import com.mcy.springbootshiro.service.SysUserService;


import org.apache.shiro.SecurityUtils;


import org.apache.shiro.authc.*;


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.apache.shiro.subject.Subject;


import org.apache.shiro.util.ByteSource;


import org.springframework.beans.factory.annotation.Autowired;


import java.util.Collection;


import java.util.HashSet;


import java.util.List;


import java.util.Set;


public class UserRealm extends AuthorizingRealm {


@Autowired


private SysUserService userService;


/**


  • 授权逻辑方法


**/


@Override


protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {


System.out.println("执行授权");


//获取当前登录对象


Subject subject = SecurityUtils.getSubject();


SysUser user = (SysUser)subject.getPrincipal();


if(user != null){


SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();


// 角色与权限字符串集合


Collection<String> rolesCollection = new HashSet<>();


//获得当前用户的角色


List<SysRole> roles = user.getRoles();


for(SysRole role : roles){


rolesCollection.add(role.getName());


}


//添加当前用户的角色权限,用于判断可以访问那些功能


info.addStringPermissions(rolesCollection);


return info;


}


return null;


}


/**


  • 认证


**/


@Override


protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {


System.out.println("执行认证");


// 编写 shiro 判断逻辑,判断用户名和密码


UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;


// 判断用户名


SysUser bean = userService.findByUsername(token.getUsername());


//用户名不存在


if(bean == null){


throw new UnknownAccountException();


}


//以账号作为加密的盐值


ByteSource credentialsSalt = ByteSourc


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


e.Util.bytes(bean.getUsername());


// 判断密码,


return new SimpleAuthenticationInfo(bean, bean.getPassword(),


credentialsSalt, getName());


}


}


其中密码加密使用的是 MD5 加密,加密代码如下:


public static void main(String[] args){


String hashAlgorithName = "MD5";


//加密密码


String password = "123456";


//加密次数


int hashIterations = 1024;


//账号作为加密的盐值


ByteSource credentialsSalt = ByteSource.Util.bytes("admin");


Object obj = new SimpleHash(hashAlgorithName, password, credentialsSalt, hashIterations);


System.out.println(obj);


}

3、编写控制器

新建 IndexController 测试控制器。这里持久层框架使用的是 SpringDataJpa,查询只需遵循查询方法命名规范即可,所以这里就直接写控制器代码了。想进一步了解 SpringDataJpa 的小伙伴,请移步:Spring-Data-Jpa入门。


IndexController 控制器代码如下:


import com.mcy.springbootshiro.entity.SysRole;


import com.mcy.springbootshiro.entity.SysUser;


import com.mcy.springbootshiro.service.SysRoleService;


import org.apache.shiro.SecurityUtils;


import org.apache.shiro.authc.IncorrectCredentialsException;


import org.apache.shiro.authc.UnknownAccountException;


import org.apache.shiro.authc.UsernamePasswordToken;


import org.apache.shiro.subject.Subject;


import org.springframework.beans.factory.annotation.Autowired;


import org.springframework.stereotype.Controller;


import org.springframework.ui.Model;


import org.springframework.web.bind.annotation.RequestMapping;


@Controller


public class IndexController {


@Autowired


private SysRoleService roleService;


@RequestMapping({"/index", "/"})


public String index(){


return "login";


}


@RequestMapping(value = "/login")


public String login(String username, String password, Model model){


//1.获取 subject


Subject subject = SecurityUtils.getSubject();


//2.封装用户数据


UsernamePasswordToken token = new UsernamePasswordToken(username, password);


try {


//3.执行登录方法


subject.login(token);


//登录成功


return "redirect:/mian";


} catch (UnknownAccountException e) {


//e.printStackTrace();


//登录失败:用户名不存在


model.addAttribute("msg", "用户名不存在");


return "login";


} catch (IncorrectCredentialsException e) {


//e.printStackTrace();


//登录失败:用户名不存在


model.addAttribute("msg", "密码输入有误");


return "login";


}


}


@RequestMapping(value = "/mian")


public String main(){


SysUser user = (SysUser) SecurityUtils.getSubject().getPrincipal();


System.out.println(user.getName());


//登录成功后,输出对应的角色和菜单


for(SysRole role: user.getRoles()){


System.out.println(role.getName()+"=====角色");


for(SysRole roles : role.getChildren()){


System.out.println(roles.getName()+"===="+role.getName()+"角色对应的菜单");


}


}


return "main";


}


@RequestMapping("/logout")


public String logout(){


Subject subject = SecurityUtils.getSubject();


if (subject != null) {


subject.logout();


}


return "redirect:/main";


}


@RequestMapping("/unAuth")


public String unAuth(){


return "unAuth";


}


@RequestMapping("/system")


public String system(){


return "system";


}


@RequestMapping("/user")


public String user(){


return "user";


}


}

4、编写页面

用户头像

Java高工P7

关注

还未添加个人签名 2021.11.08 加入

还未添加个人简介

评论

发布
暂无评论
SpringBoot整合Shiro(完整版),java学习网站