经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Java » 查看文章
Shiro快速入门
来源:cnblogs  作者:蚊蚊蚊蚊蚊170624  时间:2018/10/20 15:37:51  对本文有异议

写在前面:

  最近项目中使用了Shiro,虽然不是自己在负责这一块,但还是抽空学习了下,也可以让自己对shiro有基本的了解。毕竟Shiro安全框架在项目中还是挺常用的。

 

  对于Apache Shiro的基本概念就不在这里一一描述了,资料网上都有,主要还是记录下代码相关的,能够先让自己快速学会使用。

  这里的demo(可以测试登录认证,登出,以及授权)主要使用的是ssh框架,所以前提是要将ssh的项目框架搭起来,并导入shiro相关的jar包,然后才是编写配置shiro的相关代码。

  1.shiro相关配置文件的编写

  web.xml

  1. <!-- shiro 过滤器 start -->
  2. <!--spring容器查找名字为shiroFilter(filter-name)的bean并把所有Filter的操作委托给它。-->
  3. <filter>
  4. <filter-name>shiroFilter</filter-name>
  5. <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
  6. <!-- 设置true由servlet容器控制filter的生命周期 -->
  7. <init-param>
  8. <param-name>targetFilterLifecycle</param-name>
  9. <param-value>true</param-value>
  10. </init-param>
  11. </filter>
  12. <filter-mapping>
  13. <filter-name>shiroFilter</filter-name>
  14. <url-pattern>/*</url-pattern>
  15. </filter-mapping>
  16. <!-- shiro 过滤器 end -->

  shiro的配置文件applicationContext-shiro.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
  6.  
  7. <!--配置自定义Realm,需要继承AuthorizingRealm-->
  8. <bean id="myRealm" class="com.myshiro.shiro.MyRealm">
  9. </bean>
  10.  
  11. <!--配置SecurityManager-->
  12. <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
  13. <property name="realm" ref="myRealm"/>
  14. </bean>
  15.  
  16. <!--实现自己的登出过滤器-->
  17. <bean id="signOutFilter" class="com.myshiro.shiro.SignOutFilter">
  18. <!--配置登出重定向的路径-->
  19. <property name="redirectUrl" value="/logout.jsp"/>
  20. </bean>
  21.  
  22. <!-- 配置 ShiroFilter bean: 该 bean 的 id 必须和 web.xml 文件中配置的 shiro filter 的 name 一致 -->
  23. <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
  24. <property name="securityManager" ref="securityManager"/>
  25. <!--配置登录页面,当未认证发送请求时,默认跳转的页面,即登录页面-->
  26. <property name="loginUrl" value="/views/login.jsp"/>
  27. <!--没有授权默认跳转的页面-->
  28. <property name="unauthorizedUrl" value="/noPermission.jsp"/>
  29. <!--配置登出过滤器-->
  30. <property name="filters">
  31. <map>
  32. <entry key="logout" value-ref="signOutFilter"></entry>
  33. </map>
  34. </property>
  35. <!--配置资源过滤器链-->
  36. <property name="filterChainDefinitions">
  37. <value>
  38. <!--anon表示不拦截,直接放行-->
  39. /login = anon
  40. <!-- authc 表示需要认证后才能访问,即需要登录后才可以访问,否则跳转到上面配置的登录页面-->
  41. /authTest = authc
  42. <!-- perms 表示需要有对应的权限才能访问的,
  43. 此处perms表示要登录认证成功,并且有对应的pernissionTest权限才可以进行访问
  44. 浏览器输入../permissionTest,回车,如果没有通过登录认证,则跳转到上面配置的登录页面;否则去进行授权验证,
  45. 如果,授权验证没有通过,则跳转到上面配置的未授权跳转的页面,否则可以访问对应的资源
  46. -->
  47. /permissionTest = perms[/permissionTest]
  48. <!--当角色是admin的时候才可以访问-->
  49. /permissionTest2 = roles[admin]
  50. <!--表示在访问url为signOut时,此时会执行登出logout操作,
  51. 这里如果不自定义登出过滤器,会默认使用LogoutFilter过滤器来自动完成登出操作,并不需要实现controller层对应的signOut方法
  52. 也可以自定义登出过滤器,需要继承LogoutFilter过滤器,这里我自定义了登出过滤器
  53. -->
  54. /signOut = logout
  55. </value>
  56. </property>
  57. </bean>
  58. </beans>

  配置完后,记得使用<import resource="classpath:configs/applicationContext-shiro.xml"/>将其导入进spring配置文件中。

  2.自定义实现的Realm

  1. public class MyRealm extends AuthorizingRealm{
  2. @Resource
  3. private UserService userService;
  4. /**
  5. * 授权
  6. * 此方法 只有在shiro的配置文件中配置了权限才会进行调用,例如配置了role,permission
  7. * @param pc
  8. * @return
  9. */
  10. @Override
  11. protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pc) {
  12. //根据自己系统规则的需要编写获取授权信息,这里为了快速入门只获取了用户对应角色的资源url信息
  13. //获取当前登录输入的用户名
  14. String username = (String) pc.fromRealm(getName()).iterator().next();
  15. if (username != null) {
  16. User user = null;
  17. try {
  18. //根据用户名查询对应的user
  19. user = userService.getByUserName(username);
  20. } catch (Exception e) {
  21. e.printStackTrace();
  22. }
  23. //根据用户获取对应的role,根据role获取对应的permission
  24. Set<Role> roleSet = user.getRoleSet();
  25. List<String> pers = new ArrayList<>();
  26. for(Role r:roleSet){
  27. Set<Permission> permissionSet = r.getPermissionSet();
  28. for(Permission p:permissionSet){
  29. pers.add(p.getUrl());
  30. }
  31. }
  32. if (pers != null && !pers.isEmpty()) {
  33. SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
  34. for (String each : pers) {
  35. //将权限资源添加到用户信息中 会与配置文件中配置的对应权限做对比
  36. info.addStringPermission(each);
  37. }
  38. return info;
  39. }
  40. }
  41. return null;
  42. }
  43. /**
  44. * 认证,登录验证
  45. * @param at
  46. * @return
  47. * @throws AuthenticationException
  48. */
  49. @Override
  50. protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken at) throws AuthenticationException {
  51. //获取存进shiro token中的用户信息,(token里的信息在Controller层的login方法里存的)
  52. UsernamePasswordToken token = (UsernamePasswordToken) at;
  53. String username = token.getUsername();
  54. if (username != null && !"".equals(username)) {
  55. User user = null;
  56. try {
  57. //根据用户名去数据库中查询对应的user
  58. user = userService.getByUserName(username);
  59. if (user != null) {
  60. //将数据库中的用户名,密码拿去和存在shiro token中的用户输入的用户名,密码做对比
  61. return new SimpleAuthenticationInfo(user.getUserName(), user.getPassword(), getName());
  62. }
  63. } catch (Exception e) {
  64. e.printStackTrace();
  65. }
  66. }
  67. return null;
  68. }
  69. }

  3.自定义实现的LogoutFilter

  1. public class SignOutFilter extends LogoutFilter{
  2. @Override
  3. protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
  4. Subject subject = getSubject(request,response);
  5. String redirectUrl = getRedirectUrl(request,response,subject);
  6. try{
  7. subject.logout();
  8. }catch (Exception e){
  9. e.printStackTrace();
  10. }
  11. issueRedirect(request,response,redirectUrl);
  12. //这里返回false 代表不再去执行controller层的方法,
  13. // true代表还会去执行(如果需要在登出的controller里自定义一些东西,例如清除session或者cookie的一些信息,
  14. // 这个时候只需要返回true)
  15. return true;
  16. }
  17. }

  4.Controller层的相关方法

  1. @Controller("LoginAction")
  2. public class LoginAction extends BaseAction{
  3. @Resource
  4. private UserService userService;
  5. //接收表单填写的用户名 密码
  6. private String userName;
  7. private String password;
  8. public String login(){
  9. Subject subject = SecurityUtils.getSubject();
  10. //判断当前登录用户是否已经被认证,即是否已经登录了,如果已经登录了,再次发送登录的请求,就不再进行认证了
  11. if(!subject.isAuthenticated()){
  12. //没有登录 进行登录认证
  13. //将登录的用户名,密码存进shiro token中
  14. UsernamePasswordToken token = new UsernamePasswordToken(userName, password);
  15. try{
  16. //去自己的MyRealm类中执行doGetAuthenticationInfo()方法,进行登录认证
  17. subject.login(token);
  18. } catch ( UnknownAccountException e ) {
  19. System.out.println("用户未注册!");
  20. return "error";
  21. } catch ( IncorrectCredentialsException e ) {
  22. System.out.println("密码错误!!");
  23. return "error";
  24. } catch ( LockedAccountException e ) {
  25. System.out.println("该账户不可用~");
  26. return "error";
  27. } catch ( ExcessiveAttemptsException e ) {
  28. System.out.println("尝试次数超限!!");
  29. return "error";
  30. }
  31. return "success";
  32. }
  33. return "success";
  34. }
  35. //认证测试
  36. public void authTest(){
  37. System.out.println("authTest------进来了");
  38. }
  39. //权限授权测试
  40. public void permissionTest(){
  41. System.out.println("permissionTest--------进来了");
  42. }
  43. //登出测试
  44. public String signOut(){
  45. System.out.println("controller---登出---------");
  46. //实现对session或者其他信息的清除
  47. return "success";
  48. }
  49. @Override
  50. public String getUserName() {
  51. return userName;
  52. }
  53. public void setUserName(String userName) {
  54. this.userName = userName;
  55. }
  56. public String getPassword() {
  57. return password;
  58. }
  59. public void setPassword(String password) {
  60. this.password = password;
  61. }
  62. }

 

  对应的struts.xml中action访问路径以及对应返回资源视图的配置,以及对应的各种jsp页面这里就不再贴代码了。 

 

  测试:

 

  在表单中,填写对应的用户名,密码,然后提交,会去访问/login,此访问地址,在shiro配置中为anon,故直接放行,去controller层的login方法,然后执行到subject.login(token);,会去MyRealm中执行doGetAuthenticationInfo()方法,去验证登录信息,验证后再返回到controller层的login方法中继续执行,根据不同的验证结果,返回对应的结果视图。

 

  登录成功后,在浏览器地址栏输入..../signOut,由于shiro配置文件为logout,则会执行登出操作,这个时候会去自定义SignOutFilter里面执行preHandle()方法,由于此时返回值是true,则还需要去执行controller层的signOut()方法。

 

  登录成功后,在浏览器地址栏输入.../authTest,由于shiro配置中为authc,则需要登录认证成功后才可以继续放行访问,由于已经登录成功,则可以访问成功,会继续执行controller层的authTest()方法;如果还未登录,在浏览器地址栏输入..../authTest,此时跳转到配置的登录页面。

 

  登录成功后,在在浏览器地址栏输入.../permissionTest,由于shiro配置中为perms[/permissionTest],则需要permission权限才可以继续访问,由于已经登录成功,则会去MyRealm中的doGetAuthorizationInfo()方法中进行授权认证,若授权成功,会继续执行controller层的permissionTest()方法;如果还未登录,在浏览器地址栏输入..../permissionTest,此时跳转到配置的登录页面。

 

 

 

对于快速入门,要做到下面三个问题,就已经差不多了  

1.什么是shiro?

2.shiro可以用来干嘛?

3.shiro如何使用?

参考资料:

https://blog.csdn.net/u013142781/article/details/50629708?utm_source=blogxgwz0-----Shiro安全框架入门篇(登录验证实例详解与源码)

https://blog.csdn.net/swingpyzf/article/details/46342023/-------Apache Shiro 快速入门教程,shiro 基础教程

https://www.cnblogs.com/Mick-mod/p/8942072.html------ssh框架整合shiro权限

https://blog.csdn.net/shencange/article/details/73289801------使用shiro进行登录密码安全验证

https://blog.csdn.net/chengxuzaza/article/details/72851707------shiro实现系统的退出功能

https://blog.csdn.net/qq_34292044/article/details/79131199------Shiro实现logout操作

 

 

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号