springboot+shiro实现登陆过滤、权限认证、shiro密码加密、ehcache缓存(附demo项目)

首先说一下shiro能干什么

     Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码学和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。(百度百科)

主要功能

        三个核心组件:Subject, SecurityManager 和 Realms.

Subject:即“当前操作用户”。但是,在Shiro中,Subject这一概念并不仅仅指人,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。它仅仅意味着“当前跟软件交互的东西”。但考虑到大多数目的和用途,你可以把它认为是Shiro的“用户”概念。
  Subject代表了当前用户的安全操作,SecurityManager则管理所有用户的安全操作。
  SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。
  Realm: Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。
  从这个意义上讲,Realm实质上是一个安全相关的DAO:它封装了数据源的连接细节,并在需要时将相关数据提供给Shiro。当配置Shiro时,你必须至少指定一个Realm,用于认证和(或)授权。配置多个Realm是可以的,但是至少需要一个。
  Shiro内置了可以连接大量安全数据源(又名目录)的Realm,如LDAP、关系数据库(JDBC)、类似INI的文本配置资源以及属性文件等。如果缺省的Realm不能满足需求,你还可以插入代表自定义数据源的自己的Realm实现。


(文章最后附有本文的 密码加密算法 以及 本项目的demo资源-idea的)


demo项目结构

 

 

代码

  pom文件引入依赖


    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</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>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.8.13</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.13</version>
        </dependency>
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.2.2</version>
        </dependency>

        <!-- shiro spring. -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.2.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.2.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-ehcache</artifactId>
            <version>1.2.2</version>
        </dependency>
        <!-- 包含支持UI模版(Velocity,FreeMarker,JasperReports), 邮件服务, 脚本服务(JRuby), 缓存Cache(EHCache),
            任务计划Scheduling(uartz)。 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
        </dependency>

        <!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.4</version>
        </dependency>
    </dependencies>
ShiroConfigBean Shiro配置文件(java)

import com.example.demo.realms.MyShiroRealm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * Shiro配置Bean
 */
@Configuration
public class ShiroConfigBean {

	@Bean
	public ShiroFilterFactoryBean shirFilter(DefaultWebSecurityManager securityManager) {
		System.out.println("ShiroConfiguration.shirFilter()");
		ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();

		// 必须设置 SecurityManager
		shiroFilterFactoryBean.setSecurityManager(securityManager);
		// 拦截器.
		Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
		// 设置login URL
		shiroFilterFactoryBean.setLoginUrl("/login");
		// 登录成功后要跳转的链接
		shiroFilterFactoryBean.setSuccessUrl("/LoginSuccess.action");
		// 未授权的页面
		shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized.action");
		// src="jquery/jquery-3.2.1.min.js" 生效
		filterChainDefinitionMap.put("/jquery/*", "anon");
		// 设置登录的URL为匿名访问,因为一开始没有用户验证
		filterChainDefinitionMap.put("/login.action", "anon");
		
		filterChainDefinitionMap.put("/Exception.class", "anon");
		// 我写的url一般都是xxx.action,根据你的情况自己修改
		filterChainDefinitionMap.put("/*.action", "authc");
		// 退出系统的过滤器
		filterChainDefinitionMap.put("/logout", "logout");
		// 现在资源的角色
		filterChainDefinitionMap.put("/admin.html", "roles[admin]");
		// filterChainDefinitionMap.put("/user.html", "roles[user]");
		// 最后一班都,固定格式
		filterChainDefinitionMap.put("/**", "authc");
		shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
		return shiroFilterFactoryBean;
	}

	/*
	 * 凭证匹配器 (由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了
	 * 所以我们需要修改下doGetAuthenticationInfo中的代码; )
	 */
	@Bean
	public HashedCredentialsMatcher hashedCredentialsMatcher() {
		HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
		hashedCredentialsMatcher.setHashAlgorithmName("md5");// 散列算法:这里使用MD5算法;
		hashedCredentialsMatcher.setHashIterations(1024);// 散列的次数,比如散列两次,相当于md5(md5(""));
		return hashedCredentialsMatcher;
	}

	@Bean
	public MyShiroRealm myShiroRealm() {
		MyShiroRealm myShiroRealm = new MyShiroRealm();
		myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
		return myShiroRealm;
	}

	@Bean
	public DefaultWebSecurityManager securityManager() {
		DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		// 注入自定义的realm;
		securityManager.setRealm(myShiroRealm());
		// 注入缓存管理器;
		securityManager.setCacheManager(ehCacheManager());

		return securityManager;
	}

	/*
	 * 开启shiro aop注解支持 使用代理方式;所以需要开启代码支持;
	 */
	@Bean
	public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(
			DefaultWebSecurityManager securityManager) {
		AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
		authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
		return authorizationAttributeSourceAdvisor;
	}

	/**
	 * DefaultAdvisorAutoProxyCreator,Spring的一个bean,由Advisor决定对哪些类的方法进行AOP代理。
	 */
	@Bean
	@ConditionalOnMissingBean
	public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
		DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
		defaultAAP.setProxyTargetClass(true);
		return defaultAAP;
	}

	/*
	 * shiro缓存管理器;
	 * 需要注入对应的其它的实体类中-->安全管理器:securityManager可见securityManager是整个shiro的核心;
	 */
	@Bean
	public EhCacheManager ehCacheManager() {
		System.out.println("ShiroConfiguration.getEhCacheManager()");
		EhCacheManager cacheManager = new EhCacheManager();
		cacheManager.setCacheManagerConfigFile("classpath:ehcache.xml");
		return cacheManager;
	}

}

realms(*)

     

package com.example.demo.realms;

import com.example.demo.service.UserService;
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.util.ByteSource;

import java.util.HashSet;
import java.util.Set;
/**
 * realm实现类,用于实现具体的验证和授权方法
 * @author Bean
 *
 */
public class MyShiroRealm extends AuthorizingRealm {

	/**
	 * 方面用于加密 参数:AuthenticationToken是从表单穿过来封装好的对象
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		System.out.println("doGetAuthenticationInfo:" + token);

		// 将AuthenticationToken强转为AuthenticationToken对象
		UsernamePasswordToken upToken = (UsernamePasswordToken) token;

		// 获得从表单传过来的用户名
		String username = upToken.getUsername();

		// 从数据库查看是否存在用户
		UserService userService = new UserService();

		// 如果用户不存在,抛此异常
		if (!userService.selectUsername(username)) {
			throw new UnknownAccountException("无此用户名!");
		}

		// 认证的实体信息,可以是username,也可以是用户的实体类对象,这里用的用户名
		Object principal = username;
		// 从数据库中查询的密码
		Object credentials = userService.selectPassword(username);
		// 颜值加密的颜,可以用用户名
		ByteSource credentialsSalt = ByteSource.Util.bytes(username);
		// 当前realm对象的名称,调用分类的getName()
		String realmName = this.getName();

		// 创建SimpleAuthenticationInfo对象,并且把username和password等信息封装到里面
		// 用户密码的比对是Shiro帮我们完成的
		SimpleAuthenticationInfo info = null;
		info = new SimpleAuthenticationInfo(principal, credentials, credentialsSalt, realmName);
		return info;
	}

	// 用于授权
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

		System.out.println("MyShiroRealm的doGetAuthorizationInfo授权方法执行");

		// User user=(User)
		// principals.fromRealm(this.getClass().getName()).iterator().next();//获取session中的用户
		// System.out.println("在MyShiroRealm中AuthorizationInfo(授权)方法中从session中获取的user对象:"+user);

		// 从PrincipalCollection中获得用户信息
		Object principal = principals.getPrimaryPrincipal();
		System.out.println("ShiroRealm  AuthorizationInfo:" + principal.toString());

		// 根据用户名来查询数据库赋予用户角色,权限(查数据库)
		Set<String> roles = new HashSet<>();
		Set<String> permissions = new HashSet<>();
//		2018.09.14更新
		//		给用户添加user权限 (没有进行判断、对所有的用户给user权限)
		if("user".equals(principal)){
			roles.add("user");
			permissions.add("user:query");
		}
//		当用户名为admin时 为用户添加权限admin  两个admin可以理解为连个字段
		if ("admin".equals(principal)) {
			roles.add("admin");
			permissions.add("admin:query");
		}
//		为用户添加visit游客权限,在url中没有为visit权限,所以,所有的操作都没权限
		if("visit".equals(principal)){
			roles.add("visit");
			permissions.add("visit:query");
		}
//              更新以上代码
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roles);
		//添加权限
		info.setStringPermissions(permissions);
		return info;
		// return null;
	}

}
handler(controller)

           Ahandler

                    

package com.example.demo.handler;

import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class Ahandler {

	// 登录的url
	@RequestMapping({ "/login", "/" })
	public String indexHtml() {
		return "/index";
	}

	// 属于user角色@RequiresRoles("user")
	// 必须同时属于user和admin角@RequiresRoles({ "user", "admin" })
	// 属于user或者admin之一;修改logical为OR 即可@RequiresRoles(value = { "user", "admin"},
	// logical = Logical.OR)

	
	@RequestMapping("/showUserHtml.action")
	@RequiresRoles(value = { "user", "admin"},logical = Logical.OR)
	@RequiresPermissions("user:query")
	public String userHtml() {
		return "/user";
	}

	
	@RequestMapping("/showAdminHtml.action")
	@RequiresRoles("admin")
    @RequiresPermissions("admin:query")
	public String adminHtml() {
		
		return "/admin";
	}

	@RequestMapping("/unauthorized.action")
	public String unauthorized() {
		return "/abc";
	}

	@RequestMapping("/LoginSuccess.action")
	public String listHtml() {
		return "/list";
	}
	
	
	@RequestMapping("/error.action")
	public String error() {
		int a=1/0;
		return "/abc";
	}

}
       LoginHandler
package com.example.demo.handler;

import com.example.demo.service.UserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.UnauthorizedException;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpSession;
import java.util.Map;
/*
 * 登陆的controller
 */
@Controller
public class LoginHandler {

	@Autowired
	private UserService userService;

	@RequestMapping("/login.action")
	public String login(String username, String password, Map<String, Object> map, HttpSession session) {
		System.out.println(username + "---" + password);
		// 获得当前Subject
		Subject currentUser = SecurityUtils.getSubject();
		// 验证用户是否验证,即是否登录
		if (!currentUser.isAuthenticated()) {
			String msg = "";
			// 把用户名和密码封装为 UsernamePasswordToken 对象
			UsernamePasswordToken token = new UsernamePasswordToken(username, password);

			// remembermMe记住密码
			token.setRememberMe(true);
			try {
				// 执行登录.
				currentUser.login(token);

				// 登录成功...
				return "redirect:/LoginSuccess.action";
			} catch (IncorrectCredentialsException e) {
				msg = "登录密码错误";
				System.out.println("登录密码错误!!!" + e);
			} catch (ExcessiveAttemptsException e) {
				msg = "登录失败次数过多";
				System.out.println("登录失败次数过多!!!" + e);
			} catch (LockedAccountException e) {
				msg = "帐号已被锁定";
				System.out.println("帐号已被锁定!!!" + e);
			} catch (DisabledAccountException e) {
				msg = "帐号已被禁用";
				System.out.println("帐号已被禁用!!!" + e);
			} catch (ExpiredCredentialsException e) {
				msg = "帐号已过期";
				System.out.println("帐号已过期!!!" + e);
			} catch (UnknownAccountException e) {
				msg = "帐号不存在";
				System.out.println("帐号不存在!!!" + e);
			} catch (UnauthorizedException e) {
				msg = "您没有得到相应的授权!";
				System.out.println("您没有得到相应的授权!" + e);
			} catch (Exception e) {
				System.out.println("出错!!!" + e);
			}
			map.put("msg", msg);
			return "/index";
		}

		// 登录成功,重定向到LoginSuccess.action
		return "redirect:/LoginSuccess.action";

	}

}

service业务逻辑

package com.example.demo.service;

import java.util.ArrayList;
import java.util.List;

import org.springframework.stereotype.Service;

import com.example.demo.entity.User;
/**
 * User的service,这里面的数据时静态数据,不查询数据库了
 * @author lenovo
 *
 */
@Service
public class UserService {

	// 用户的集合
	private List<User> users = new ArrayList<>();

	public UserService() {
		// 从数据库查出来的用户名,密码,这是是静态数据(密码是123456)
		users.add(new User("admin", "038bdaf98f2037b31f1e75b5b4c9b26e"));
		users.add(new User("user", "098d2c478e9c11555ce2823231e02ec1"));
	}

	// 判断是否用户名是否存在
	public boolean selectUsername(String username) {
		for (User user : users) {
			if (user.getUsername().equals(username)) {
				return true;
			}
		}
		return false;
	}

	// 根据用户返回查询的密码
	public String selectPassword(String username) {
		for (User user : users) {
			if (user.getUsername().equals(username)) {
				return user.getPassword();
			}
		}
		return "";

	}

}
exception全局异常捕捉
package com.example.demo.exception;

import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * 全局异常捕捉类
 * 
 * @author Bean
 *
 */
@ControllerAdvice
public class AllException {

	/// 角色權权限异常捕捉
	@ExceptionHandler(value = UnauthorizedException.class)
	@ResponseBody // 在返回自定义相应类的情况下必须有,这是@ControllerAdvice注解的规定
	public String roleException(UnauthorizedException e) {
		System.out.println("---------------------->" + e);
		return "角色权限不够!!!";
		// return "/abc";
	}

	// 其它异常异常捕捉
	@ExceptionHandler(value = Exception.class)
	@ResponseBody // 在返回自定义相应类的情况下必须有,这是@ControllerAdvice注解的规定
	public String allException(Exception e) {
		System.out.println("---------------------->" + e);
		return "系統出现异常!!!";
	}

}

entity实体类

package com.example.demo.entity;
/**
 * 实体类 
 * @author Bean
 *
 */
public class User {

	private Integer id;// 主键
	private String username;// 用户名
	private String password;// 密码

	@Override
	public String toString() {
		return "User [id=" + id + ", username=" + username + ", password=" + password + "]";
	}

	/**
	 * @return the id
	 */
	public Integer getId() {
		return id;
	}

	/**
	 * @param id
	 *            the id to set
	 */
	public void setId(Integer id) {
		this.id = id;
	}

	/**
	 * @return the username
	 */
	public String getUsername() {
		return username;
	}

	/**
	 * @param username
	 *            the username to set
	 */
	public void setUsername(String username) {
		this.username = username;
	}

	/**
	 * @return the password
	 */
	public String getPassword() {
		return password;
	}

	/**
	 * @param password
	 *            the password to set
	 */
	public void setPassword(String password) {
		this.password = password;
	}

	public User(String username, String password) {

		this.username = username;
		this.password = password;
	}

	public User() {

	}

}

ehcache 进行缓存权限数据 配置

<!--
  ~ Hibernate, Relational Persistence for Idiomatic Java
  ~
  ~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
  ~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
  -->
<ehcache>
       <!-- 存储最大对象数 -->
       <!-- 是否永久保存 -->
       <!-- 最大空闲时间  单位:秒 -->
       <!-- 存活时间 -->
       <!-- 溢出到磁盘 -->
       <!-- 磁盘上最大存储的对象数 -->
       <!-- 服务器重启后磁盘上的数据是否有效 -->
       <!-- 每隔多长时间去开启一次线程清理数据 -->
       <!-- 淘汰策略    最近一段时间利用率低的会被优先清理掉 -->

    <!-- Sets the path to the directory where cache .data files are created.

         If the path is a Java System Property it is replaced by
         its value in the running VM.

         The following properties are translated:
         user.home - User's home directory
         user.dir - User's current working directory
         java.io.tmpdir - Default temp file path -->
    <diskStore path="java.io.tmpdir"/>


    <!--Default Cache configuration. These will applied to caches programmatically created through
        the CacheManager.

        The following attributes are required for defaultCache:

        maxInMemory       - Sets the maximum number of objects that will be created in memory
        eternal           - Sets whether elements are eternal. If eternal,  timeouts are ignored and the element
                            is never expired.
        timeToIdleSeconds - Sets the time to idle for an element before it expires. Is only used
                            if the element is not eternal. Idle time is now - last accessed time
        timeToLiveSeconds - Sets the time to live for an element before it expires. Is only used
                            if the element is not eternal. TTL is now - creation time
        overflowToDisk    - Sets whether elements can overflow to disk when the in-memory cache
                            has reached the maxInMemory limit.

        -->
    <defaultCache
        maxElementsInMemory="10000"
        eternal="false"
        timeToIdleSeconds="120"
        timeToLiveSeconds="120"
        overflowToDisk="true"
        />

    <!--Predefined caches.  Add your cache configuration settings here.
        If you do not have a configuration for your cache a WARNING will be issued when the
        CacheManager starts

        The following attributes are required for defaultCache:

        name              - Sets the name of the cache. This is used to identify the cache. It must be unique.
        maxInMemory       - Sets the maximum number of objects that will be created in memory
        eternal           - Sets whether elements are eternal. If eternal,  timeouts are ignored and the element
                            is never expired.
        timeToIdleSeconds - Sets the time to idle for an element before it expires. Is only used
                            if the element is not eternal. Idle time is now - last accessed time
        timeToLiveSeconds - Sets the time to live for an element before it expires. Is only used
                            if the element is not eternal. TTL is now - creation time
        overflowToDisk    - Sets whether elements can overflow to disk when the in-memory cache
                            has reached the maxInMemory limit.

        -->

    <!-- Sample cache named sampleCache1
        This cache contains a maximum in memory of 10000 elements, and will expire
        an element if it is idle for more than 5 minutes and lives for more than
        10 minutes.

        If there are more than 10000 elements it will overflow to the
        disk cache, which in this configuration will go to wherever java.io.tmp is
        defined on your system. On a standard Linux system this will be /tmp"
        -->
    <cache name="sampleCache1"
        maxElementsInMemory="10000"
        eternal="false"
        timeToIdleSeconds="300"
        timeToLiveSeconds="600"
        overflowToDisk="true"
        />

    <!-- Sample cache named sampleCache2
        This cache contains 1000 elements. Elements will always be held in memory.
        They are not expired. -->
    <cache name="sampleCache2"
        maxElementsInMemory="1000"
        eternal="true"
        timeToIdleSeconds="0"
        timeToLiveSeconds="0"
        overflowToDisk="false"
        /> -->

    <!-- Place configuration for your caches following -->

</ehcache>

html代码

index.html  登陆页面

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"></meta>
<title>Insert title here</title>
<script type="text/javascript" src="jquery/jquery-3.2.1.min.js"></script>

<script th:inline="javascript">  
    /*<![CDATA[*/  
     $(function(){  
        var msg = [[${msg}]];  
        if(msg!="null"&&msg!=null&&msg!=""){
    		alert(msg);
    	}
        
        
     }); 
    /*]]>*/  
  </script>



</head>
<body>
	<h1>Login HTML</h1>
	<h4 th:text="${msg}"></h4>

	<form action="login.action" method="post">
		用户名:<input type="text" name="username" /><br /> 密码:<input
			type="password" name="password" /><br /> <input type="submit"
			value="Submit" />
	</form>
</body>
</html>

list.html  登陆成功页

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"></meta>
<title>Insert title here</title>
</head>
<body>
<h1>list HTML</h1>
<a href="showUserHtml.action">user html</a>
<a href="showAdminHtml.action">admin html</a>
<a href="error.action">error 1/0  html</a>
<a href="logout">退出</a>


</body>
</html>

abc.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"></meta>
<title>Insert title here</title>
</head>
<body>
	<h1>abc HTML</h1>

	<h4 th:text="${msg}"></h4>

</body>
</html>

admin.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"></meta>
<title>Insert title here</title>
</head>
<body>
<h1>admin HTML</h1>


</body>
</html>

user.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"></meta>
<title>Insert title here</title>
</head>
<body>
<h1>user HTML</h1>


</body>
</html>

                                         以上就是所有demo代码了...

测试的话 

                 先使用admin登陆  密码123456  ,权限方面都能通过

                 再使用user登陆 密码123456    ,权限方面showAdminHtml.action没有访问权限

对应代码资源         https://download.csdn.net/download/qq_32786139/10661538

本文密码加密算法

		//盐值用的用的是对用户名的加密(测试用的"lisi")
                ByteSource credentialsSalt01 = ByteSource.Util.bytes("lisi");
		Object salt = null;//盐值
		Object credential = "123456";//密码
		String hashAlgorithmName = "MD5";//加密方式
                //1024指的是加密的次数
		Object simpleHash = new SimpleHash(hashAlgorithmName, credential,
				credentialsSalt01, 1024);
		System.out.println("加密后的值----->" + simpleHash);

直接写个main方法测试就可以了

猜你喜欢

转载自blog.csdn.net/qq_32786139/article/details/82658197