本文主要介绍了在Spring Boot2项目中整合Shiro实现登录认证。本文假设读者已经对Shiro和基于RBAC的权限控制系统有了基本的认识。
本项目没有数据库,也就没有dao层,所有的用户和密码均在Service层采用硬编码。
特别提醒:因为代码块中的
@
符号在博客发布过程中会导致代码格式混乱,所以@
都是用双斜杠注释了。
通过idea的Spring Initializr
新建工程spring-boot2-shiro-project
,选择web模块即可。在项目根目录添加service
、controller
和config
文件夹,项目目录如下图所示:
这一步对于整合shiro不是必须的
import java.util.Scanner,为了在项目中返回统一的结果,我们新建一个泛型类,包含属性:结果代码code
、结果信息message
和结果数据data
,其中data采用泛型,代码如下:
public class Result<T> {private ResultCodeEnum code;private String message;private T data;public ResultCodeEnum getCode() {return code;}public Result() {}public Result setCode(ResultCodeEnum resultCode) {this.code = resultCode;return this;}public String getMessage() {return message;}public Result setMessage(String message) {this.message = message;return this;}public T getData() {return data;}public Result setData(T data) {this.data = data;return this;}
}
再新建一个枚举类ResultCodeEnum
,列举所有的返回代码code
:
public enum ResultCodeEnum {SUCCESS(200),//成功FAIL(400),//失败UNAUTHORIZED(401),//未认证(签名错误)NOT_FOUND(404),//接口不存在INTERNAL_SERVER_ERROR(500);//服务器内部错误public int code;ResultCodeEnum(int code) {this.code = code;}public int getCode() {return this.code;}
}
再建一个结果生成类ResultGenerator
,减少重复代码,保证返回值的统一性
public class ResultGenerator {private static final String DEFAULT_SUCCESS_MESSAGE = "SUCCESS";//成功public static Result genSuccessResult() {return new Result().setCode(ResultCodeEnum.SUCCESS).setMessage(DEFAULT_SUCCESS_MESSAGE);}public static <T> Result<T> genSuccessResult(T data) {return new Result().setCode(ResultCodeEnum.SUCCESS).setMessage(DEFAULT_SUCCESS_MESSAGE).setData(data);}public static Result genFailResult(String message) {return new Result().setCode(ResultCodeEnum.FAIL).setMessage(message);}public static Result genUnauthorizedResult() {return new Result().setCode(ResultCodeEnum.UNAUTHORIZED).setMessage("权限不足!");}
}
新建IndexController
package top.zhaodongxx.controller;import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import top.zhaodongxx.result.Result;
import top.zhaodongxx.result.ResultGenerator;/*** <P></P>** @author zhaodong* @version v1.0* @email zhaodongxx@outlook.com* @since 2018/3/30 21:55*/@RestController
public class IndexController {@GetMapping("/helloworld")public Result helloWorld() {return ResultGenerator.genSuccessResult("helloworld");}
}
运行SpringBoot2ShiroProjectApplication.java
即可启动该Spring Boot项目。
访问路径127.0.0.1:8080/helloworld
项目运行成功!
在Spring Boot2项目中整合Shiro主要分为四步
DefaultWebSecurityManager
和ShiroFilterFactoryBean
beanpropertybindingresult,Shiro提供了一个启动器来完成与 Spring Boot 的集成。
<dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring-boot-starter</artifactId><version>1.4.0</version>
</dependency>
因为本节只是介绍身份认证,所以只提供一个最简单的 Java Class 配置
package top.zhaodongxx.config;import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;/*** <P></P>** @author zhaodong* @version v1.0* @email zhaodongxx@outlook.com* @since 2018/3/30 22:41*/
@Configuration
public class ShiroConfig {/*** 自定义的Realm*/@Bean(name = "myShiroRealm")public MyShiroRealm myShiroRealm(){MyShiroRealm myShiroRealm = new MyShiroRealm();return myShiroRealm;}@Beanpublic DefaultWebSecurityManager securityManager(){DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();设置realm.securityManager.setRealm(myShiroRealm());return securityManager;}@Bean(name = "shiroFilter")public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();shiroFilterFactoryBean.setSecurityManager(securityManager);return shiroFilterFactoryBean;}
}
安全管理器DefaultWebSecurityManager
是Shiro的核心模块,ShiroFilterFactoryBean
用来配置需要被拦截的请求,被拦截下来的请求交给安全管理器管理。myShrioRealm
在idea中现在还是红色的,因为我们还没有写。
新建一个服务,用来模拟从数据库中取出用户信息,
package top.zhaodongxx.service;import org.springframework.stereotype.Service;/*** @author zhaodong* @version v1.0* @email zhaodongxx@outlook.com* @since 2018/3/30 22:59*/
@Service
public class ShiroService {public String getPasswordByUsername(String username){switch (username){case "liming":return "123";case "hanli":return "456";default:return null;}}
}
Realm 是控制认证和授权的核心部分,也是开发人员必须自己实现的部分。
自定义的Realm通过继承AuthorizingRealm
类,实现它的两个方法:doGetAuthorizationInfo
和doGetAuthenticationInfo
实现自己的认证和授权逻辑,其中doGetAuthenticationInfo
处理授权逻辑暂时不实现。
package top.zhaodongxx.shiro;import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
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 top.zhaodongxx.service.ShiroService;import javax.annotation.Resource;/**** @author zhaodong* @version v1.0* @email zhaodongxx@outlook.com* @since 2018/3/30 22:55*/
public class MyShiroRealm extends AuthorizingRealm {@Resourcepublic ShiroService shiroService;/*** 授权*/@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();return authorizationInfo;}/*** 登录认证*/@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {//获取用户账号String username = token.getPrincipal().toString();String password = shiroService.getPasswordByUsername(username);if (password != null) {AuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(username, //认证通过后,存放在session,一般存放user对象password, //用户数据库中的密码getName()); //返回Realm名return authenticationInfo;}return null;}
}
AuthenticationException
是Shiro封装的异常,如果登录认证没有成功就会抛出这个异常。
package top.zhaodongxx.controller;import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import top.zhaodongxx.result.Result;
import top.zhaodongxx.result.ResultGenerator;/**** @author zhaodong* @version v1.0* @email zhaodongxx@outlook.com* @since 2018/3/30 23:05*/
@RestController
public class LoginController {@PostMapping("/doLogin")public Result doLogin(String username, String password) {Subject subject = SecurityUtils.getSubject();UsernamePasswordToken token = new UsernamePasswordToken(username, password);try {subject.login(token);} catch (AuthenticationException e) {token.clear();return ResultGenerator.genFailResult("登录失败,用户名或密码错误!");}return ResultGenerator.genSuccessResult("登录成功");}
}
@SpringBootApplication、重新启动项目。
通过postman
访问127.0.0.1:8080/doLogin?username=liming&password=1231
,
登陆失败
访问127.0.0.1:8080/doLogin?username=liming&password=123
,
登录成功
至此,通过Shiro实现了身份认证。
版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。
工作时间:8:00-18:00
客服电话
电子邮件
admin@qq.com
扫码二维码
获取最新动态