认证
先搭建基本的项目框架,本项目不使用配置文件,全部使用配置类配置springmvc,之前还没有接触过,这个项目也算是补充了:
pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>testProject</artifactId>
<groupId>org.rhett</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<spring.version>5.2.3.RELEASE</spring.version>
</properties>
<packaging>war</packaging>
<artifactId>security-sprimgmvc</artifactId>
<dependencies>
<!-- spring & spring mvc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>{spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>{spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
<!-- 工具 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
</dependencies>
<build>
<finalName>security‐springmvc</finalName>
<pluginManagement>
<plugins>
<!-- tomcat插件启动 -->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
</plugin>
<plugin>
<artifactId>maven‐resources‐plugin</artifactId>
<configuration>
<encoding>utf‐8</encoding>
<useDefaultDelimiters>true</useDefaultDelimiters>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/*</include>
</includes>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</configuration>
<version>3.1.0</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
配置类
@Configuration
@ComponentScan(basePackages = "com.rhett.security",
excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,value = Controller.class)})
//相当于application.xml
public class ApplicationConfig {
}
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.rhett.security",
includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,value = Controller.class)})
//相当于web.xml,实现WebMvcConfigurer
public class WebConfig implements WebMvcConfigurer {
//视图解析器
@Bean
public InternalResourceViewResolver viewResolver(){
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/view/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("login");
}
}
Spring容器初始化:这个类实现自WebApplicationInitializer
,spring容器启动的时候会加载WebApplicationInitializer接口的所有实现类。
public class SpringApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
//spring容器,相当于加载application.xml
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{ApplicationConfig.class};
}
//servletContext,相当于加载web.xml
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{WebConfig.class};
}
//url-mapping
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
实体类
用户信息:
@Data
@AllArgsConstructor
public class UserDto {
private String id;
private String username;
private String password;
private String fullname;
private String mobile;
}
封装用户提交的登录参数:
@Data
public class AuthenticationRequest {
private String username;
private String password;
}
认证service
public interface AuthenticationService {
UserDto authentication(AuthenticationRequest request);
}
实现:
@Service
public class AuthenticationServiceImpl implements AuthenticationService{
private Map<String,UserDto> userMap = new HashMap<>();
//模拟数据库数据
{
userMap.put("zhangsan",new UserDto("1010","zhangsan","123","张三"));
userMap.put("lisi",new UserDto("1011","lisi","456","李四","144553"));
}
@Override
public UserDto authentication(AuthenticationRequest request) {
//校验参数是否为空
if(request == null
|| StringUtils.isEmpty(request.getUsername())
|| StringUtils.isEmpty(request.getPassword())){
throw new RuntimeException("账号和密码为空");
}
//根据账号去查询数据库
UserDto user = getUserDto(request.getUsername());
if(user==null){
throw new RuntimeException("查询不到该用户");
}
if(!request.getPassword().equals(user.getPassword())){
throw new RuntimeException("账号或密码错误");
}
return user;
}
//假装这是一个查询数据库的方法
private UserDto getUserDto(String userName){
return userMap.get(userName);
}
}
controller
@RestController
public class LoginController {
@Autowired
private AuthenticationService authenticationService;
@PostMapping(value = "/login",produces = "text/plain;charset=utf-8")
public String login(AuthenticationRequest request){
UserDto userDto = authenticationService.authentication(request);
return userDto.getUsername()+"登录成功";
}
}
视图
部署在webapp/WEB-INF/view/
下
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>用户登录</title>
</head>
<body>
<form action="login" method="post">
用户:<input type="text" name="username"><br/>
密码:<input type="password" name="password"><br/>
<input type="submit" value="登录"/>
</form>
</body>
</html>
现在就可以进行登录了。
会话
要实现会话,就是将登录信息写入session中,首先取一个session名,可以写在UserDto中:
@Data
@AllArgsConstructor
public class UserDto {
//session名
public static final String SESSION_USER_KEY = "_user";
private String id;
private String username;
private String password;
private String fullname;
private String mobile;
}
在登录的controller获取session,并将用户信息存入session:
@PostMapping(value = "/login",produces = "text/plain;charset=utf-8")
public String login(AuthenticationRequest request, HttpSession session){
UserDto userDto = authenticationService.authentication(request);
//存入session
session.setAttribute(UserDto.SESSION_USER_KEY,userDto);
return userDto.getUsername()+"登录成功";
}
写一个资源验证一下:
@GetMapping(value = "/r/r1",produces = {"text/plain;charset=utf-8"})
public String r1(HttpSession session){
String fullname = null;
Object object = session.getAttribute(UserDto.SESSION_USER_KEY);
if(object == null){
fullname = "匿名";
}else {
UserDto userDto = (UserDto) object;
fullname = userDto.getFullname();
}
return fullname+"访问资源r1";
}
先登录,再访问,可以看到用户信息被识别了:

授权
更改controller,新增一个资源r2:
@GetMapping(value = "/r/r2",produces = {"text/plain;charset=utf-8"})
public String r2(HttpSession session){
String fullname = null;
Object object = session.getAttribute(UserDto.SESSION_USER_KEY);
if(object == null){
fullname = "匿名";
}else {
UserDto userDto = (UserDto) object;
fullname = userDto.getFullname();
}
return fullname+"访问资源r2";
}
给用户增加一个表示权限的字段:
@Data
@AllArgsConstructor
public class UserDto {
public static final String SESSION_USER_KEY = "_user";
private String id;
private String username;
private String password;
private String fullname;
private String mobile;
//用户权限
private Set<String> authorities;
}
更改service的初始化代码块:
{
Set<String> authorities1 = new HashSet<>();
authorities1.add("p1");//p1和/r/r1对应
Set<String> authorities2 = new HashSet<>();
authorities2.add("p2");//p2和/r/r2对应
userMap.put("zhangsan",new UserDto("1010","zhangsan","123","张三","133443",authorities1));
userMap.put("lisi",new UserDto("1011","lisi","456","李四","144553",authorities2));
}
写一个拦截器用于权限验证:
@Component
public class SimpleAuthenticationInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,Object handler) throws Exception{
//取出用户身份信息
Object object = request.getSession().getAttribute(UserDto.SESSION_USER_KEY);
if(object == null){
writeContent(response,"请登录");
}
UserDto userDto = (UserDto) object;
//请求的uri
String requestURI = request.getRequestURI();
if(userDto.getAuthorities().contains("p1")&&requestURI.contains("r/r1")){
return true;
}
if(userDto.getAuthorities().contains("p2")&&requestURI.contains("r/r2")){
return true;
}
writeContent(response,"没有权限,拒绝访问");
return false;
}
private void writeContent(HttpServletResponse response, String msg) throws IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter writer = response.getWriter();
writer.write(msg);
writer.close();
}
}
在WebConfig中配置拦截器:
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.rhett.security",
includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,value = Controller.class)})
public class WebConfig implements WebMvcConfigurer {
@Autowired
SimpleAuthenticationInterceptor simpleAuthenticationInterceptor;
//视图解析器
@Bean
public InternalResourceViewResolver viewResolver(){
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/view/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("login");
}
//配置拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(simpleAuthenticationInterceptor).addPathPatterns("/r/**");
}
}
验证:登录zhangsan,访问r1正常,访问r2提示权限不够

原创文章,作者:彭晨涛,如若转载,请注明出处:https://www.codetool.top/article/springmvc%e5%9f%ba%e4%ba%8esession%e5%ae%9e%e7%8e%b0%e7%94%a8%e6%88%b7%e8%ae%a4%e8%af%81%e3%80%81%e4%bc%9a%e8%af%9d%e3%80%81%e6%8e%88%e6%9d%83/