船志健康项目-移动端开发-手机快速登录、权限控制9
一、需求分析
手机快速登录功能,就是通过短信验证码的方式进行登录。这种方式相对于用户名密码登录方式,用户不需要记忆自己的密码,只需要通过输入手机号并获取验证码就可以完成登录,是目前比较流行的登录方式。

二、手机快速登录
1. 页面调整
登录页面为/pages/login.html
1.1 发送验证码
为获取验证码按钮绑定事件,并在事件对应的处理函数中校验手机号,如果手机号输入正确则显示30秒倒计时效果并发送ajax请求,发送短信验证码
<div class="input-row"> <label>手机号</label> <div class="loginInput"> <input v-model="loginInfo.telephone" id='account' type="text" placeholder="请输入手机号"> <input id="validateCodeButton" @click="sendValidateCode()" type="button" style="font-size: 12px" value="获取验证码"> </div> </div>
<script> var vue = new Vue({ el:'#app', data:{ loginInfo:{}//登录信息 }, methods:{ //发送验证码 sendValidateCode(){ var telephone = this.loginInfo.telephone; //对手机号进行合法性校验 if (!checkTelephone(telephone)) { this.$message.error('请输入正确的手机号'); return false; } validateCodeButton = $("#validateCodeButton")[0]; clock = window.setInterval(doLoop, 1000); //一秒执行一次 //发送ajax请求,发送手机验证码 axios.post("/validateCode/send4Login.do?telephone=" + telephone).then((response) => { if(!response.data.flag){ //验证码发送失败 this.$message.error('验证码发送失败,请检查手机号输入是否正确'); } }); } } }); </script>
在ValidateCodeController中提供send4Login方法,调用短信服务发送验证码并将验证码保存到redis
//用户在线体检预约发送验证码
@RequestMapping("/send4Login")
public Result send4Login(String telephone){
//随机生成6位数字验证码
Integer validateCode = ValidateCodeUtils.generateValidateCode(6);
//给用户发送验证码
try {
SMSUtils.sendShortMessage(SMSUtils.VALIDATE_CODE,telephone,validateCode.toString());
} catch (ClientException e) {
e.printStackTrace();
//验证码发送失败
//return new Result(false, MessageConstant.SEND_VALIDATECODE_FAIL);
}
System.out.println("send validateCode is :"+validateCode);
//将生成的验证码缓存到redis,5分钟后失效
jedisPool.getResource().setex(telephone+ RedisMessageConstant.SENDTYPE_LOGIN,5*60,validateCode.toString());
return new Result(true,MessageConstant.SEND_VALIDATECODE_SUCCESS);
}
1.2 提交登录请求
为登录按钮绑定事件
<div class="btn yes-btn"><a @click="login()" href="#">登录</a></div>
//登录
login(){
var telephone = this.loginInfo.telephone;
if (!checkTelephone(telephone)) {
this.$message.error('请输入正确的手机号');
return false;
}
//发送ajax请求,将表单数据提交到Controller进行登录处理
axios.post("/member/login.do",this.loginInfo).then((response) => {
if(response.data.flag){
//登录成功,跳转到会员首页
window.location.href="member.html";
}else{
//失败,提示失败信息
this.$message.error(response.data.message);
}
});
}
2. 后台代码
2.1 Controller
在health_mobile工程中创建MemberController并提供login方法进行登录检查,处理逻辑为:
1、校验用户输入的短信验证码是否正确,如果验证码错误则登录失败
2、如果验证码正确,则判断当前用户是否为会员,如果不是会员则自动完成会员注册
3、向客户端写入Cookie,内容为用户手机号
4、将会员信息保存到Redis,使用手机号作为key,保存时长为30分钟
package com.itheima.controller;
import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.itheima.constant.MessageConstant;
import com.itheima.constant.RedisMessageConstant;
import com.itheima.entity.Result;
import com.itheima.pojo.Member;
import com.itheima.service.MemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import redis.clients.jedis.JedisPool;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.Map;
/**
* 处理会员相关操作
* 会员登录
*/
@RestController
@RequestMapping("/member")
public class MemberController {
@Reference
private MemberService memberService;
@Autowired
private JedisPool jedisPool;
@RequestMapping("/login")
public Result login(HttpServletResponse response, @RequestBody Map map){
String telephone = (String) map.get("telephone");
String validateCode = (String) map.get("validateCode");
//从Redis中获取缓存的验证码,key为手机号+RedisMessageConstant.SENDTYPE_LOGIN
String validateCodeInRedis = jedisPool.getResource().get(telephone + RedisMessageConstant.SENDTYPE_LOGIN);
//校验手机验证码,将用户输入的验证码和Redis中保存的验证码进行比对
if(validateCodeInRedis == null || !validateCodeInRedis.equals(validateCode)){
//验证码输入错误
return new Result(false, MessageConstant.VALIDATECODE_ERROR);
}
//验证码输入正确
//检查当前用户是否为会员,根据手机号判断,如果不是会员则自动完成注册
Member member = memberService.findByTelephone(telephone);
if(member == null){
//用户不是会员,需要添加到会员表,完成注册
member = new Member();
member.setRegTime(new Date());
member.setPhoneNumber(telephone);
memberService.add(member);
}
//登录成功
//向客户端浏览器写入Cookie,内容为手机号,跟踪用户
Cookie cookie = new Cookie("login_member_telephone",telephone);
cookie.setPath("/");//路径
cookie.setMaxAge(60*60*24*30);//有效期30天
response.addCookie(cookie);
//保存会员信息到Redis中
String json = JSON.toJSON(member).toString();
jedisPool.getResource().setex(telephone,30*60,json);
return new Result(true,MessageConstant.LOGIN_SUCCESS);
}
}
//根据手机号查询会员
public Member findByTelephone(String telephone);
public void add(Member member);
2.3 服务实现类
@Override
public Member findByTelephone(String telephone) {
return memberDao.findByTelephone(telephone);
}
@Override
public void add(Member member) {
String password = member.getPassword();
if(password != null){
//使用md5将明文密码进行加密
password = MD5Utils.md5(password);
member.setPassword(password);
}
memberDao.add(member);
}
2.4 Dao接口
public Member findByTelephone(String telephone);
public void add(Member member);
2.5 Mapper映射文件
<!--根据手机号查询会员--> <select id="findByTelephone" parameterType="string" resultType="com.itheima.pojo.Member"> select * from t_member where phoneNumber = #{phoneNumber} </select> <!--新增会员--> <insert id="add" parameterType="com.itheima.pojo.Member"> <selectKey resultType="java.lang.Integer" order="AFTER" keyProperty="id"> SELECT LAST_INSERT_ID() </selectKey> insert into t_member(fileNumber,name,sex,idCard,phoneNumber,regTime,password,email,birthday,remark) values (#{fileNumber},#{name},#{sex},#{idCard},#{phoneNumber},#{regTime},#{password},#{email},#{birthday},#{remark}) </insert>
三、权限控制
1. 认证和授权概念
前面我们已经完成了传智健康后台管理系统的部分功能,例如检查项管理、检查组管理、套餐管理、预约设置等。接下来我们需要思考2个问题:
问题1:在生产环境下我们如果不登录后台系统就可以完成这些功能操作吗?
答案显然是否定的,要操作这些功能必须首先登录到系统才可以。
问题2:是不是所有用户,只要登录成功就都可以操作所有功能呢?
答案是否定的,并不是所有的用户都可以操作这些功能。不同的用户可能拥有不同的权限,这就需要进行授权了。
认证:系统提供的用于识别用户身份的功能,通常提供用户名和密码进行登录其实就是在进行认证,认证的目的是让系统知道你是谁。
授权:用户认证成功后,需要为用户授权,其实就是指定当前用户可以操作哪些功能。
本章节就是要对后台系统进行权限控制,其本质就是对用户进行认证和授权。
2. 权限模块数据模型
前面已经分析了认证和授权的概念,要实现最终的权限控制,需要有一套表结构支撑:
用户表t_user、权限表t_permission、角色表t_role、菜单表t_menu、用户角色关系表t_user_role、角色权限关系表t_role_permission、角色菜单关系表t_role_menu。
表之间关系如下图:

通过上图可以看到,权限模块共涉及到7张表。在这7张表中,角色表起到了至关重要的作用,其处于核心位置,因为用户、权限、菜单都和角色是多对多关系。
接下来我们可以分析一下在认证和授权过程中分别会使用到哪些表:
认证过程:只需要用户表就可以了,在用户登录时可以查询用户表t_user进行校验,判断用户输入的用户名和密码是否正确。
授权过程:用户必须完成认证之后才可以进行授权,首先可以根据用户查询其角色,再根据角色查询对应的菜单,这样就确定了用户能够看到哪些菜单。然后再根据用户的角色查询对应的权限,这样就确定了用户拥有哪些权限。所以授权过程会用到上面7张表。
3. 在项目中应用Spring Security
将Spring Security框架应用到 后台系统中进行权限控制,其本质就是认证和授权。
在真正进行认证和授权之前需要对表里的数据进行管理,即我们需要开发如下一些功能:
1、权限数据管理(增删改查)
2、菜单数据管理(增删改查)
3、角色数据管理(增删改查、角色关联权限、角色关联菜单)
4、用户数据管理(增删改查、用户关联角色)
鉴于时间关系,我们不再实现这些数据管理的代码开发。我们可以直接将数据导入到数据库中即可。
3.1 导入Spring Security环境
第一步:在health_parent父工程的pom.xml中导入Spring Security的maven坐标(添加到dependencyManagement中)
<!-- 安全框架 --> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>${spring.security.version}</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>${spring.security.version}</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-taglibs</artifactId> <version>${spring.security.version}</version> </dependency>
第二步:在health_backend工程的web.xml文件中配置用于整合Spring Security框架的过滤器DelegatingFilterProxy
<filter> <!-- DelegatingFilterProxy委派过滤器,用于整合第三方框架 整合Spring Security时过滤器的名称必须为springSecurityFilterChain,否则会抛出NoSuchBeanDefinitionException异常 --> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <!--访问index.html就会进入到springsecurity框架--> <url-pattern>/*</url-pattern> </filter-mapping>
3.2 实现认证和授权
第一步:在health_backend工程中按照Spring Security框架要求提供SpringSecurityUserService,并且实现UserDetailsService接口
package com.itheima.security; import com.alibaba.dubbo.config.annotation.Reference; import com.itheima.pojo.Permission; import com.itheima.pojo.Role; import com.itheima.service.UserService; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; import java.util.Set; @Component public class SpringSecurityUserService implements UserDetailsService { //使用dubbo通过网络远程调用服务提供方获取数据库中的用户信息 @Reference private UserService userService; //根据用户名查询数据库获取用户信息 @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { System.out.println("username:"+username); com.itheima.pojo.User user = userService.findByUsername(username); if(user == null){//用户不存在 return null; } //动态为用户授权 List<GrantedAuthority> list = new ArrayList<>(); Set<Role> roles = user.getRoles(); for (Role role : roles) { //授予角色 list.add(new SimpleGrantedAuthority(role.getKeyword())); Set<Permission> permissions = role.getPermissions(); for (Permission permission : permissions) { //授权 list.add(new SimpleGrantedAuthority(permission.getKeyword())); } } UserDetails userDetails = new User(username,user.getPassword(),list); //将用户信息返回给框架,框架会进行密码比对(页面提交的密码和数据库中查询的密码进行比对) return userDetails; } }
第二步:创建UserService服务接口、服务实现类、Dao接口、Mapper映射文件等(health_interface)
package com.itheima.service;
import com.itheima.pojo.User;
/**
* 用户服务接口
*/
public interface UserService {
public User findByUsername(String username);
}
package com.itheima.service.impl; import com.alibaba.dubbo.config.annotation.Service; import com.itheima.dao.PermissionDao; import com.itheima.dao.RoleDao; import com.itheima.dao.UserDao; import com.itheima.pojo.Permission; import com.itheima.pojo.Role; import com.itheima.pojo.User; import com.itheima.service.SetmealService; import com.itheima.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import java.util.Set; @Service(interfaceClass = UserService.class) @Transactional public class UserServiceImpl implements UserService { @Autowired private UserDao userDao; @Autowired private RoleDao roleDao; @Autowired private PermissionDao permissionDao; //根据用户名查询数据库获取用户信息、角色信息、权限信息 @Override public User findByUsername(String username) { //查询用户基本信息,不包含用户的角色 User user = userDao.findByUsername(username); if(user == null){ return null; } Integer userId = user.getId(); //根据用户id查询对应的角色 Set<Role> roles = roleDao.findByUserId(userId); if(roles != null && roles.size() > 0){ for (Role role : roles) { Integer roleId = role.getId(); //根据角色id查询对应的权限 Set<Permission> permissions = permissionDao.findByRoleId(roleId); if(permissions != null && permissions.size() > 0){ role.setPermissions(permissions); } } user.setRoles(roles); } return user; } }
package com.itheima.dao;
import com.itheima.pojo.User;
public interface UserDao {
public User findByUsername(String username);
}
package com.itheima.dao; import com.itheima.pojo.Role; import java.util.Set; public interface RoleDao { public Set<Role> findByUserId(Integer userId); }
package com.itheima.dao; import com.itheima.pojo.Permission; import java.util.Set; public interface PermissionDao { public Set<Permission> findByRoleId(Integer roleId); }
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="com.itheima.dao.UserDao" > <select id="findByUsername" parameterType="String" resultType="com.itheima.pojo.User"> select * from t_user where username = #{username} </select> </mapper>
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="com.itheima.dao.RoleDao" > <!--根据用户id查询关联的角色--> <select id="findByUserId" parameterType="int" resultType="com.itheima.pojo.Role"> select r.* from t_role r, t_user_role ur where r.id = ur.role_id and ur.user_id = #{userId} </select> </mapper>
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="com.itheima.dao.PermissionDao" > <!--根据角色id查询关联的权限--> <select id="findByRoleId" parameterType="int" resultType="com.itheima.pojo.Permission"> select p.* from t_permission p, t_role_permission rp where p.id = rp.permission_id and rp.role_id = #{roleId} </select> </mapper>
第三步:修改health_backend工程中的springmvc.xml文件,修改dubbo批量扫描的包路径
<!--批量扫描--> <dubbo:annotation package="com.itheima" />
注意:此处原来扫描的包为com.itheima.controller,现在改为com.itheima包的目的是需要将我们上面定义的SpringSecurityUserService也扫描到,因为在SpringSecurityUserService的 loadUserByUsername方法中需要通过dubbo远程调用名称为UserService的服务。
第四步:在health_backend工程中提供spring-security.xml配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:security="http://www.springframework.org/schema/security" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd"> <!--配置哪些资源匿名可以访问,不需要进行权限校验,即不登录可以访问--> <security:http security="none" pattern="/login.html" /> <security:http security="none" pattern="/css/**" /> <security:http security="none" pattern="/js/**" /> <security:http security="none" pattern="/img/**" /> <security:http security="none" pattern="/plugins/**" /> <!-- http:用于定义相关权限控制 auto-config:是否自动配置 设置为true时框架会提供默认的一些配置,例如提供默认的登录页面、登出处理等 设置为false时需要显示提供登录表单配置,否则会报错 use-expressions:是否适用spring security提供的表达式来描述权限。用于指定intercept-url中的access属性是否使用表达式 --> <security:http auto-config="true" use-expressions="true"> <security:headers> <!--设置在页面可以通过iframe访问受保护的页面,默认为不允许访问,main.html是通过iframe嵌套的--> <security:frame-options policy="SAMEORIGIN" /> </security:headers> <!--只要认证通过就可以访问--> <security:intercept-url pattern="/pages/**" access="isAuthenticated()" /> <!--如果要使用自己指定的页面作为登录页面,必须配置登录表单,页面提交的登录表单请求是由框架负责处理 login-page:指定登录页面访问url login-processing-url:对应表单action请求地址 default-target-url:登录认证成功后跳转的url authentication-failure-url:认证失败后跳转的url --> <security:form-login login-page="/login.html" username-parameter="username" password-parameter="password" login-processing-url="/login.do" default-target-url="/pages/main.html" always-use-default-target="true" authentication-failure-url="/login.html" /> <!-- csrf:对应CsrfFilter过滤器 disabled:是否启用CsrfFilter过滤器,如果使用自定义登录页面需要关闭此项,否则登录操作会被禁用(403)--> <security:csrf disabled="true"></security:csrf> <!-- logout:退出登录 logout-url:退出登录操作对应的请求路径 logout-success-url:退出登录后的跳转页面 invalidate-session:将当前session失效 --> <security:logout logout-url="/logout.do" logout-success-url="/login.html" invalidate-session="true"/> </security:http> <!--配置密码加密对象--> <bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" /> <!--authentication-manager:认证管理器,用于处理认证操作--> <security:authentication-manager> <!--authentication-provider:认证提供者,执行具体的认证逻辑--> <!--user-service-ref:用于获取用户信息,提供给authentication-provider进行认证--> <security:authentication-provider user-service-ref="springSecurityUserService"> <!--指定密码加密策略--> <security:password-encoder ref="passwordEncoder" /> </security:authentication-provider> </security:authentication-manager> <!--开启注解方式权限控制--> <security:global-method-security pre-post-annotations="enabled" /> </beans>
第五步:在springmvc.xml文件中引入spring-security.xml文件
<import resource="spring-security.xml"/>
第六步:在Controller的方法上加入权限控制注解,此处以CheckItemController为例
package com.itheima.controller;
import com.alibaba.dubbo.config.annotation.Reference;
import com.itheima.constant.MessageConstant;
import com.itheima.entity.PageResult;
import com.itheima.entity.QueryPageBean;
import com.itheima.entity.Result;
import com.itheima.pojo.CheckItem;
import com.itheima.service.CheckItemService;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 检查项管理
*/
@RestController
@RequestMapping("/checkitem")
public class CheckItemController {
@Reference //到zookeeper注册中心查找服务
private CheckItemService checkItemService;
//新增检查项
@PreAuthorize("hasAuthority('CHECKITEM_ADD')")//权限校验
@RequestMapping(value = "/add",method = RequestMethod.POST)
public Result add(@RequestBody CheckItem checkItem){
try{
checkItemService.add(checkItem);
}catch (Exception e){
e.printStackTrace();
return new Result(false, MessageConstant.ADD_CHECKITEM_FAIL);
}
return new Result(true,MessageConstant.ADD_CHECKITEM_SUCCESS);
}
//检查项分页查询
@PreAuthorize("hasAuthority('CHECKITEM_QUERY')")//权限校验
@RequestMapping("/findPage")
public PageResult findPage(@RequestBody QueryPageBean queryPageBean){
PageResult pageResult = checkItemService.pageQuery(queryPageBean);
return pageResult;
}
//删除检查项
@RequestMapping("/delete")
@PreAuthorize("hasAuthority('CHECKITEM_DELETE')") //权限校验
public Result delete(Integer id){
try{
checkItemService.delete(id);
}catch (Exception e){
e.printStackTrace();
return new Result(false, MessageConstant.DELETE_CHECKITEM_FAIL);
}
return new Result(true,MessageConstant.DELETE_CHECKITEM_SUCCESS);
}
@PreAuthorize("hasAuthority('CHECKITEM_EDIT')")//权限校验
@PostMapping("/edit")
public Result edit(@RequestBody CheckItem checkItem){
try{
checkItemService.edit(checkItem);
}catch (Exception e){
return new Result(false,MessageConstant.EDIT_CHECKITEM_FAIL);
}
return new Result(true,MessageConstant.EDIT_CHECKITEM_SUCCESS);
}
}
第七步:修改页面,没有权限时提示信息设置,此处以checkitem.html中的handleDelete方法为例
//权限不足提示
showMessage(r){
if(r == 'Error: Request failed with status code 403'){
//权限不足
this.$message.error('无访问权限');
return;
}else{
this.$message.error('未知错误');
return;
}
}
// 删除
handleDelete(row) {//row其实是一个json对象,json对象的结构为{}
this.$confirm("确认删除当前选中记录吗?","提示",{
type:'warning'
}).then(()=>{
//点击确定按钮,发送ajax请求,将检查项交给Controller进行处理
axios.get("/checkitem/delete.do?id="+row.id).then((response)=>{
if(response.data.flag){
//删除成功
this.$message({
message: response.data.message,
type: 'success'
});
//调用分页,获取最新分页数据
this.findPage();
}else{
//删除失败
this.$message.error(response.data.message);
}
}).catch((r)=>{
this.showMessage(r);
});
}).catch(() => {
//点击取消按钮
this.$message({
message: "操作已取消",
type: 'info'
});
});
}
3.3 显示用户名
前面我们已经完成了认证和授权操作,如果用户认证成功后需要在页面展示当前用户的用户名。Spring Security在认证成功后会将用户信息保存到框架提供的上下文对象中,所以此处我们就可以调用Spring Security框架提供的API获取当前用户的username并展示到页面上。
实现步骤:
第一步:在health_backend工程main.html页面中修改,定义username模型数据基于VUE的数据绑定展示用户名,发送ajax 请求获取username
<script> new Vue({ el: '#app', data:{ username:null, //用户名 menuList:[] }, created(){ //发送ajax请求获取当前登录用户名 axios.get("/user/getUsername.do").then((res)=>{ if(res.data.flag){ this.username = res.data.data; } }); } }); </script>
<div class="avatar-wrapper"> <img src="../img/user2-160x160.jpg" class="user-avatar"> <!--展示用户名--> {{username}} </div>
第二步:创建UserController并提供getUsername方法
package com.itheima.controller;
import com.itheima.constant.MessageConstant;
import com.itheima.entity.Result;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 登录用户
*/
@RestController
@RequestMapping("/user")
public class UserController {
//获取当前登录用户的用户名
@RequestMapping("/getUsername")
public Result getUsername(){
//当Spring Security完成认证后,会将当前用户信息保存到框架提供的上下文对象
try{
User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
System.out.println("user: "+user);
return new Result(true, MessageConstant.GET_USERNAME_SUCCESS,user.getUsername());
}catch (Exception e){
return new Result(false, MessageConstant.GET_USERNAME_FAIL);
}
}
}
通过debug调试可以看到Spring Security框架在其上下文中保存的用户相关信息:

3.4 用户退出
第一步:在main.html中提供的退出菜单上加入超链接
<el-dropdown-item divided> <span style="display:block;"><a href="/logout.do">退出</a></span> </el-dropdown-item>
第二步:在spring-security.xml文件中配置
<!-- logout:退出登录 logout-url:退出登录操作对应的请求路径 logout-success-url:退出登录后的跳转页面 invalidate-session:将当前session失效 --> <security:logout logout-url="/logout.do" logout-success-url="/login.html" invalidate-session="true"/>
浙公网安备 33010602011771号