一、spring boot与shiro的使用,实现登录操作,项目结构图如图所示:
二、pom.xml依赖配置:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.6.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<!-- spring boot 中web socket服务依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-Java</artifactId>
<version>5.1.44</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.4</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<!-- log4j依赖 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
三、数据库表结构
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_name` varchar(16) NOT NULL,
`user_password` varchar(32) NOT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `role` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`role_name` varchar(32) NOT NULL,
`user_id` int(11) NOT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `permission` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`permission` varchar(32) NOT NULL,
`role_id` int(11) NOT NULL,
PRIMARY KEY (`id`)
);
四、shiro的过滤配置,使用@Configuration注解;
/**
* @ClassName: MonitorShiroConfiguration.java
* @Description: 过滤配置;
* @author wangmin
* @date 2018年6月4日-下午5:11:54
* @version 1.0V
*/
@Configuration
public class MonitorShiroConfiguration {
/**
* 将自定义的验证方式加入到容器中;
* @return
* @date 2018年6月4日-下午5:13:53
* @author wangmin
*/
@Bean
public MonitorShiroRealm monitorShiroRealm () {
return new MonitorShiroRealm();
}
/**
* 权限管理,配置主要是Realm的管理认证;
* @return
* @date 2018年6月4日-下午5:20:53
* @author wangmin
*/
@Bean
public org.apache.shiro.mgt.SecurityManager securityManager () {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(monitorShiroRealm());
return securityManager;
}
/**
* Filter工厂,设置对应的过滤条件和跳转条件;
* @param securityManager
* @return
* @date 2018年6月4日-下午5:23:52
* @author wangmin
*/
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean (org.apache.shiro.mgt.SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
Map<String, String> map = new HashMap<String, String>();
// 登出
map.put("/logout","logout");
// 对所有用户认证
map.put("/**","authc");
// 配置不会被拦截的链接
map.put("/web", "anon");
// 登录
shiroFilterFactoryBean.setLoginUrl("/login");
// 首页
shiroFilterFactoryBean.setSuccessUrl("/index");
// 错误页面,认证不通过跳转
shiroFilterFactoryBean.setUnauthorizedUrl("/error");
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
return shiroFilterFactoryBean;
}
/**
* 加入注解的使用,不加入这个注解不生效;
* @param securityManager
* @return
* @date 2018年6月4日-下午5:28:21
* @author wangmin
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(org.apache.shiro.mgt.SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
}
五、配置过滤条件及验证,继承AuthorizingRealm接口用户用户认证;
/**
* @ClassName: MonitorShiroRealm.java
* @Description: 配置过滤条件及验证,继承AuthorizingRealm接口用户用户认证;
* @author wangmin
* @date 2018年6月4日-下午4:48:37
* @version 1.0V
*/
public class MonitorShiroRealm extends AuthorizingRealm {
@Autowired
private ILoginService loginService;
/**
* 角色权限和对应权限添加;
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
// 获取登录用户名
String userName = String.valueOf(principalCollection.getPrimaryPrincipal());
User user = loginService.findByName(userName);
// 添加角色和权限
SimpleAuthorizationInfo author = new SimpleAuthorizationInfo();
for (Role role : user.getRoles()) {
// 添加角色
author.addRole(role.getRoleName());
for (Permission permission : role.getPermissions()) {
// 添加权限
author.addStringPermission(permission.getPermission());
}
}
return author;
}
/**
* 用户验证;
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
/**在进行post请求时,会先验证,然后再到请求*/
if (authenticationToken.getPrincipal() == null) {
return null;
}
// 获取用户信息
String userName = String.valueOf(authenticationToken.getPrincipal());
User user = loginService.findByName(userName);
if (user == null) {
return null;
} else {
// 验证authenticationToken和simpleAuthenticationInfo的信息
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(userName, user.getPassword(), getName());
return authenticationInfo;
}
}
}
六、实体类
/**
* @ClassName: User.java
* @Description: 用户实体类;
* @author wangmin
* @date 2018年6月4日-下午4:25:20
* @version 1.0V
*/
@Entity
@Data
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private Long userId;
@Column(name = "user_name")
private String userName;
@Column(name = "user_password")
private String password;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "user")
private List<Role> roles;
}
/***********************************************************************************/
/**
* @ClassName: Role.java
* @Description: 角色实体类,只考虑一个用户有多个角色,不考虑多对多的关系;
* @author wangmin
* @date 2018年6月4日-下午4:27:33
* @version 1.0V
*/
@Entity
@Data
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(name = "role_name")
private String roleName;
@ManyToOne(fetch = FetchType.EAGER)
private User user;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "role")
private List<Permission> permissions;
}
/***********************************************************************************/
/**
* @ClassName: Permission.java
* @Description: 用户权限;
* @author wangmin
* @date 2018年6月4日-下午4:42:03
* @version 1.0V
*/
@Entity
@Data
public class Permission {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String permission;
@ManyToOne(fetch = FetchType.EAGER)
private Role role;
}
七、dao(Repository)层操作:
@NoRepositoryBean
public interface BaseRepository <T, I extends Serializable> extends PagingAndSortingRepository<T, I>, JpaSpecificationExecutor<T> {
}
/***********************************************************************************/
/**
* @ClassName: UserRepository.java
* @Description: "Invalid derived query! No property name found for type User!"出现这个错误是因为实体类中没有
* 某个属性(No property 属性名 found for type 类名);
* @author wangmin
* @date 2018年6月5日-上午9:06:54
* @version 1.0V
*/
public interface UserRepository extends BaseRepository<User, Long>{
User findByUserName (String name);
}
/***********************************************************************************/
public interface RoleRepository extends BaseRepository<Role, Long>{
}
八、service层
/**
* @ClassName: ILoginService.java
* @Description: 登录操作service接口类;
* @author wangmin
* @date 2018年6月4日-下午4:59:04
* @version 1.0V
*/
public interface ILoginService {
/**
* 根据用户名获取用户信息;
* @param userName
* @return
* @date 2018年6月4日-下午4:58:27
* @author wangmin
*/
User findByName (String userName);
/**
* 添加用户信息;
* @param map
* @return
* @date 2018年6月4日-下午5:45:34
* @author wangmin
*/
User addUser(Map<String, Object> map);
/**
* 添加用户角色;
* @param map
* @return
* @date 2018年6月4日-下午5:47:30
* @author wangmin
*/
Role addRole(Map<String, Object> map);
}
/***********************************************************************************/
/**
* @ClassName: LoginServiceImpl.java
* @Description: 登录操作service接口实现类;
* @author wangmin
* @date 2018年6月4日-下午4:59:29
* @version 1.0V
*/
@Service(value="loginServiceImpl")
public class LoginServiceImpl implements ILoginService {
@Autowired
private UserRepository userRepository;
@Autowired
private RoleRepository roleRepository;
/**
* 添加用户信息;
*/
@Override
public User addUser(Map<String, Object> map) {
User user = new User();
user.setUserName(String.valueOf(map.get("userName")));
user.setPassword(String.valueOf(map.get("password")));
userRepository.save(user);
return user;
}
/**
* 添加角色信息;
*/
@Override
public Role addRole(Map<String, Object> map) {
User user = userRepository.findOne(Long.valueOf(map.get("userId").toString()));
Role role = new Role();
role.setRoleName(map.get("roleName").toString());
role.setUser(user);
Permission permission1 = new Permission();
permission1.setPermission("create");
permission1.setRole(role);
Permission permission2 = new Permission();
permission2.setPermission("update");
permission2.setRole(role);
List<Permission> permissions = new ArrayList<Permission>();
permissions.add(permission1);
permissions.add(permission2);
role.setPermissions(permissions);
roleRepository.save(role);
return role;
}
/**
* 根据用户名获取用户信息;
*/
@Override
public User findByName(String userName) {
return userRepository.findByUserName(userName);
}
}
九、controller层
/**
* @ClassName: LoginController.java
* @Description: 用户登录controller;
* @author wangmin
* @date 2018年6月4日-下午5:29:34
* @version 1.0V
*/
@RestController
public class LoginController {
@Resource(name = "loginServiceImpl")
private ILoginService loginService;
/**
* 退出的时候是get请求,主要是用于退出;
* @return
* @date 2018年6月4日-下午5:55:25
* @author wangmin
*/
@RequestMapping(value = "/login",method = RequestMethod.GET)
public String login(){
return "login";
}
/**
* post登录;
* @param map
* @return
* @date 2018年6月4日-下午5:55:10
* @author wangmin
*/
@RequestMapping(value = "/login",method = RequestMethod.POST)
public String login(@RequestBody Map<String, String> map){
// 添加用户认证信息
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(
String.valueOf(map.get("username")),
String.valueOf(map.get("password")));
// 进行验证,这里可以捕获异常,然后返回对应信息
subject.login(usernamePasswordToken);
return "login";
}
/**
* 首页;
* @return
* @date 2018年6月4日-下午5:55:01
* @author wangmin
*/
@RequestMapping(value = "/index")
public String index(){
return "index";
}
/**
* 登出;
* @return
* @date 2018年6月4日-下午5:54:38
* @author wangmin
*/
@RequestMapping(value = "/logout")
public String logout(){
return "logout";
}
/**
* 错误页面展示;
* @return
* @date 2018年6月4日-下午5:54:19
* @author wangmin
*/
@RequestMapping(value = "/error",method = RequestMethod.POST)
public String error(){
return "error ok!";
}
/**
* 数据初始化;
* @param map
* @return
* @date 2018年6月4日-下午5:54:02
* @author wangmin
*/
@RequestMapping(value = "/addUser")
public String addUser(@RequestBody Map<String,Object> map){
User user = loginService.addUser(map);
return "addUser is ok! \n" + user;
}
/**
* 角色初始化;
* @param map
* @return
* @date 2018年6月4日-下午5:53:48
* @author wangmin
*/
@RequestMapping(value = "/addRole")
public String addRole(@RequestBody Map<String,Object> map){
Role role = loginService.addRole(map);
return "addRole is ok! \n" + role;
}
/**
* 注解的使用
* @return
* @date 2018年6月4日-下午5:53:33
* @author wangmin
*/
@RequiresRoles("admin")
@RequiresPermissions("create")
@RequestMapping(value = "/create")
public String create(){
return "Create success!";
}
}