当前位置:网站首页>ssm练习第四天_获取用户名_用户退出_用户crud_密码加密_角色_权限

ssm练习第四天_获取用户名_用户退出_用户crud_密码加密_角色_权限

2022-07-26 17:31:00 奇迹是执着的人创造的

文章目录

一、第一章:用户认证功能完善

第一节:显示用户名功能

使用SpringSecurity框架进行操作时,SpringSecurity会产生一个上下文对象SecurityContext,该上下文对象会被自动存储到session域中,于此同时也会将该上下文对象绑定到当前线程上,通过SecurityContext可以获得认证对象Authentication,而认证对象Authentication内部封装了principal(主角)属性,该principal就是当前用户对象User,而User对象自然包含用户名等信息。

获取过程:SecurityContext—>Authentication—>User—>username

1、获得用户名方式一:

服务器端可以通过程序API的方式获得

@RequestMapping("/showUsername")
    public void showUsername(HttpServletRequest request){
    
        //获取session对象
        HttpSession session = request.getSession();
        //从session域中获取username [框架帮你放的session key是多少呢?]
        //方法是人想的 先获取所有属性名试试
        Enumeration attributeNames = session.getAttributeNames();
        //遍历枚举类型 和遍历结果集一样
        while(attributeNames.hasMoreElements()){
    
            System.out.println(attributeNames.nextElement());
        }
        //只有一个:SPRING_SECURITY_CONTEXT
        // 顾名思义 安全框架的上下文对象 不是简单的一个个键值对 而是封装了一个类对象放到session中
        //System.out.println(session.getAttribute("SPRING_SECURITY_CONTEXT"));
        SecurityContext  securityContext = (SecurityContext) session.getAttribute("SPRING_SECURITY_CONTEXT");
        //从上下文对象中获取认证信息
        Authentication authentication = securityContext.getAuthentication();
        //Principal:首要的 (就是用户对象)--用户详情(UserDetails)
        Object principal = authentication.getPrincipal();
        User user= (User) principal;
        //获取用户名
        String username = user.getUsername();
        System.out.println(username);

        //方法二 如此重要的context不可能让你每次到session中拿 怎么也得提供个静态方法来获取吧 果不其然
        SecurityContext context = SecurityContextHolder.getContext();
        System.out.println(context==securityContext);//获得的是同一个对象 地址都一样啊(上下文对象也只可能有一个)
        User user1= (User) context.getAuthentication().getPrincipal();
        System.out.println(user1.getUsername());
    }

简单获取方法就是:

SecurityContext context = SecurityContextHolder.getContext();
User user= (User) context.getAuthentication().getPrincipal();
System.out.println(user.getUsername());

2、获得用户名方式二:

在页面中通过el表达式从session域中获得 el表达式
根据demo session中获取username的方法 不难理解这种前端获取username的写法

${sessionScope.SPRING_SECURITY_CONTEXT.authentication.principal.username}

3、获得用户名方式三:

在页面中通过SpringSecurity的标签直接获得
spring_SECURITY提供的一套标签库
既然是标签库肯定腰线引入:

<%@ taglib prefix="security" uri="http://www.springframework.org/security/tags" %>
<security:authentication property="principal.username" />

4、显示用户名效果

在这里插入图片描述

第二节:用户退出功能

在header.jsp的页面中编写超链接
就是路径写成/logout绝对路径即可 logout和/login一样 xml里配置的路径

<a href="${pageContext.request.contextPath}/logout"
	class="btn btn-default btn-flat">注销</a>

注意必须写绝对路径
在这里插入图片描述

配置时麻烦用起来太简单了

第二章:用户模块

第一节:用户列表查询功能

1、页面入口

在这里插入图片描述

2、编写Controller

@Controller
@RequestMapping("/user")
public class UserController {
    

    @Autowired
    UserService userService;

    @RequestMapping("/findAll")
    public ModelAndView findAll(){
    
        List<SysUser> users = userService.findAll();
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("users",users);
        modelAndView.setViewName("user-list");
        return modelAndView;
    }

}

3、编写Service

接口

public interface UserService extends UserDetailsService{
    

    /** * 查询全部 * @return */
    List<SysUser> findAll();
}

实现

    @Override
    public List<SysUser> findAll() {
    
        return userdao.findAll();
    }

4、编写Dao

    @Select("select * from sys_user")
    List<SysUser> findAll();

第二节:添加用户功能

1、页面入口

在这里插入图片描述

写安全框架时表和javaBean都有了

2、编写Controller

    @RequestMapping("/save")
    public String save(SysUser  user){
    
        userService.save(user);
        return "redirect:/user/findAll";
    }

3、编写Service

接口

    void save(SysUser user);

实现

    @Override
    public void save(SysUser user) {
    
        //user.setPassword(MD5Utils.md5(user.getPassword()));//md5加密穷举法可破解
        userdao.save(user);
    }

4、编写Dao

    @Insert("insert into sys_user values(user_seq.nextval,#{username},#{email},#{password},#{phoneNum},#{status})")
    void save(SysUser user);

第三节:判断唯一用户名

1、页面入口

在这里插入图片描述
编写页面

<script type="text/javascript">
		function isUniqueUsername(a) {
    
			//alert(a.value);//也能得到a 表示整个input框 dom元素类型
			//alert($("#username").val());//jquery方式肯定也能得到
			var username=$("#username").val();
			//请求controller,判断用户名是否唯一
			//不能刷新整个页面 因此必须ajax异步请求
			$.ajax({
    
				url:"${pageContext.request.contextPath}/user/isUniqueUsername",
				//data:"username="+username,//后端能收到
				data:{
    "username":username},//后端也能收到
				success:function (data) {
    
					//alert(data);
					if(data == "false"){
    //返回的是false字符串啊 转json流返回的
					    //提示用户名已经被占用 -- 设置文本框为红色,宽度为1,样式为实线
						$("#username").attr("style","border:red 2px solid");//.css用不了 因为已经有个class样式了
						//保存按钮设置为不可用
						$("#saveBtn").prop("disabled","disabled");
						//attr("disabled","true");//然后下面写false也行
                    }else{
    
					    //取消样式
                        $("#username").removeAttr("style");
                        $("#username").addClass("form-control")//如果样式没有了 需要加上原来的样式
					    //保存按钮设置为可用
                        $("#saveBtn").removeAttr("disabled");
                    }
                },
				//dataType:"text",//一般可以省略
				type:"GET"
			});
        }
</script>

注:pl/sql development 修改式查询

select * from sys_user for update;

在这里插入图片描述

2、编写Controller

springMVC返回值就3种 void string modelAndView 没有bool等其他类型 只能三选一
@ResponseBody:把结果集转成json以流的形式返回(否则会进入视图解析器跳转404页面)

    //springMVC返回值就3种 void string modelAndView 没有bool等其他类型 只能三选一
    //@ResponseBody:把结果集转成json以流的形式返回(否则会进入视图解析器跳转404页面)
    @RequestMapping("/isUniqueUsername")
    @ResponseBody
    public String isUniqueUsername(String username){
    
        LogUtils.print(username);
        Boolean b=userService.isUniqueUsername(username);
        return ""+b;//转字符串返回
    }

3、编写service

接口:

    Boolean isUniqueUsername(String username);

实现:

    @Override
    public Boolean isUniqueUsername(String username) {
    
        SysUser user = userdao.findAllUserByUsername(username);
        return user == null;
    }

4、编写Dao

注意前面的findByUsername方法需要加个条件: 关闭的用户不允许登录在这里插入图片描述
此处不管状态问题,都要判重,因此不能沿用之前的方法了

    /** * 根据用户名查询单个用户 不忽略关闭状态的用户 * @param username * @return */
    @Select("select * from sys_user where username=#{abc}")
    SysUser findAllUserByUsername(String username);

第四节:用户密码的加密操作

为了客户账户的安全性,在数据库中不能明文显示密码,所以就需要对客户端提交的密码进行加密后在存储到数据库中。原来可以使用md5、加盐加密等工具进行密码加密,目前我们使用的SpringSecurity框架本身就提供了加密工具。

0、md5加密

可以暴力破解 不大好

	@Override
    public void save(SysUser user) {
    
        //获取明文密码
        String password = user.getPassword();
        //对明文密码进行加密
        String md5Password = MD5Utils.md5(password);
        //把加密后的密码存储到user对象中
        user.setPassword(md5Password);
        userDao.save(user);
    }

1、在spring-security.xml中配置加密类BCryptPasswordEncoder

<!--创建加密工具类对象-->
<bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"></bean>

2、修改save业务方法

	@Autowired
    PasswordEncoder passwordEncoder;//上面xml中已经创建了 容器中已经有了
    @Override
    public void save(SysUser user) {
    
        //user.setPassword(MD5Utils.md5(user.getPassword()));//md5无法防止暴力破解
        user.setPassword(passwordEncoder.encode(user.getPassword()));//安全框架的加密很牛
        userdao.save(user);
    }

3、加密效果

在这里插入图片描述

4、修改登录操作

	<!-- 配置认证信息 -->
    <security:authentication-manager>
        <!--认证信息的提供者: 关联用户服务对象 - 提供账号和密码-->
        <security:authentication-provider user-service-ref="userServiceImpl"><!--使用的是ioc容器内的默认名称-->
            <!--登录时要加密密码:指定登录加密工具类-->
            <security:password-encoder ref="passwordEncoder"></security:password-encoder>
        </security:authentication-provider>
    </security:authentication-manager>

    <!--创建加密工具类对象 在下面时 此配置第1步就添加了-->
    <bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"></bean>

在这里插入图片描述
修改userServiceImpl的认证方法loadUserByUsername

@Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    
        //System.out.println(username);
        SysUser sysUser = userdao.findByUsername(username);
        if(sysUser==null) return null;
        //配置文件里没有指定角色了 需要自己创建角色对象
        //创建角色的集合对象
        Collection<GrantedAuthority> authorities=new ArrayList<>();
        //创建临时角色对象 正常情况下应该是数据库角色表中查的
        GrantedAuthority grantedAuthority = new SimpleGrantedAuthority("ROLE_USER");
        //对象添加到集合中
        authorities.add(grantedAuthority);
        //User是安全框架内实现了UserDetails接口的一个类
        //第三个参数是:角色列表对象 (此处角色名ROLE_USER自己定义 xml里需要这个名字)
        //{noop}前缀表示不加密 该把不加密去掉了
        UserDetails user = new User(sysUser.getUsername(),sysUser.getPassword(),authorities);
        return user;
    }

在这里插入图片描述

注:放在下面比较好
在这里插入图片描述

第三章:角色模块

第一节:角色表与实体的创建

1、角色表建表语句和字段含义

create sequence role_seq;

CREATE TABLE sys_role(
	id number PRIMARY KEY,
	roleName VARCHAR2(50) ,
	roleDesc VARCHAR2(50)
)

insert into sys_role values(role_seq.nextval, 'ADMIN','管理员');

select * from sys_role;

字段含义:

序号字段名称字段类型字段描述
1idbigint无意义,主键自动增长
2roleNamevarchar角色名
3roleDescvarchar角色描述

2、Role实体创建

@Data
public class Role {
    
    private Integer id;
    private String roleName;
    private String roleDesc;
}

第二节:角色列表查询功能

1、页面入口

在这里插入图片描述

2、编写Controller

@Controller
@RequestMapping("/role")
public class RoleController {
    

    @Autowired
    RoleService roleService;

    @RequestMapping("/findAll")
    public ModelAndView findAll(){
    
        List<Role> roles = roleService.findAll();
        LogUtils.print(roles);
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("roles",roles);
        modelAndView.setViewName("role-list");
        return modelAndView;
    }
}

3、编写Service

接口

    List<Role> findAll();

实现

    @Override
    public List<Role> findAll() {
    
        return roleDao.findAll();
    }

4、编写Dao

    @Select("select * from sys_role")
    List<Role> findAll();

第三节:添加角色功能

1、页面入口

在这里插入图片描述

2、编写Controller

    @RequestMapping("/save")
    public String save(Role role){
    
        LogUtils.print(role);
        roleService.save(role);
        return "redirect:findAll";
    }

3、编写Service

接口

    void save(Role role);

实现

    @Override
    public void save(Role role) {
    
        roleDao.save(role);
    }

4、编写Dao

    @Insert("insert into sys_role values(role_seq.nextval,#{roleName},#{roleDesc})")
    void save(Role role);

第四章:权限模块

第一节:权限表与实体的创建

1、权限表建表语句和字段含义

-- 权限管理
create sequence permission_seq;

-- pid关联自己表id 称为上级权限id 没有上级的pid为0
CREATE TABLE sys_permission(
	id number PRIMARY KEY,
	permissionName VARCHAR2(50) ,
	url VARCHAR2(50),
	pid number
)
select * from sys_permission for update;
select permission_seq.nextval from dual;
select * from sys_permission;

手动添加数据:
在这里插入图片描述
然后将序列刷到5 防止下次插入总是主键冲突

select permission_seq.nextval from dual;

在这里插入图片描述

字段含义:

序号字段名称字段类型字段描述
1idbigint无意义
2permissionNamevarchar权限名
3urlvarchar资源路径
4pidbigint父菜单id

注: 设置pl/sql development 执行sql自动提交事务

在这里插入图片描述

2、Permission实体创建

@Data
public class Permission {
    
    private Integer id;
    private String permissionName;
    private String url;
    private Integer pid;//写简单的pid 不能写Permission对象 随便想想也是死循环
}

第二节:权限列表查询功能

1、页面入口

在这里插入图片描述

2、编写Controller

    @RequestMapping("/findAll")
    public ModelAndView findAll(){
    
        List<Permission> permissions= permissionService.findAll();
        LogUtils.print(permissions);
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("permissions",permissions);
        modelAndView.setViewName("permission-list");
        return modelAndView;
    }

3、编写Service

接口

    List<Permission> findAll();

实现

    @Override
    public List<Permission> findAll() {
    
        return permissionDao.findAll();
    }

4、编写Dao

    @Select("select * from sys_permission")
    List<Permission> findAll();

前端没怎么改 简单的c:foreach循环

第三节:添加权限功能-回显父菜单

1、页面入口

在这里插入图片描述

<div class="col-md-2 title">父权限</div>
<div class="col-md-4 data">
	<select class="form-control select2" style="width: 100%"
			name="pid">
		<c:forEach items="${permissions}" var="p">
			<option value="${p.id}" selected="selected">${
    p.permissionName}</option>
		</c:forEach>
	</select>
</div>

2、编写Controller

    /** * 添加数据回显 * 主要就是数据库中查询所有父权限 然后在下拉选中显示出来 */
    @RequestMapping("/saveUI")
    public ModelAndView saveUI(){
    
        List<Permission> permissions=permissionService.findAllParentPermission();
        LogUtils.print(permissions);
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("permissions",permissions);
        modelAndView.setViewName("permission-add");
        return modelAndView;
    }

3、编写Service

接口

    /** * 查询所有父权限 * @return */
    List<Permission> findAllParentPermission();

实现

    @Override
    public List<Permission> findAllParentPermission() {
    
        return permissionDao.findAllParentPermission();
    }

4、编写Dao

    /** * 查询所有父权限 * @return */
    @Select("select * from sys_permission where pid=0")
    List<Permission> findAllParentPermission();

第四节:添加权限功能-保存到数据库

1、页面入口

在这里插入图片描述

2、编写Controller

    @RequestMapping("/save")
    public String save(Permission permission){
    
        LogUtils.print(permission);
        permissionService.save(permission);
        return "redirect:/permission/findAll";
    }

3、编写Service

接口

    void save(Permission permission);

实现

    @Override
    public void save(Permission permission) {
    
        permissionDao.save(permission);
    }

4、编写Dao

    /** * 保存权限 * @param permission */
    @Select("insert into sys_permission values(permission_seq.nextval,#{permissionName},#{url},#{pid})")
    void save(Permission permission);

翻博客 查看statueStr的含义

原网站

版权声明
本文为[奇迹是执着的人创造的]所创,转载请带上原文链接,感谢
https://blog.csdn.net/hza419763578/article/details/106035641