基于session的認(rèn)證授權(quán)方式-SSM
具體流程:當(dāng)用戶登陸成功后,會(huì)在服務(wù)端將用戶的相關(guān)信息保存到session中,而將發(fā)給客戶端的session_id保存到cookie中,這樣下次請(qǐng)求時(shí)帶上session_id來(lái)校驗(yàn)服務(wù)端是否存在session數(shù)據(jù),如果存在就校驗(yàn)通過(guò),如果不存在就校驗(yàn)失敗。當(dāng)用戶退出登錄或session數(shù)據(jù)過(guò)期,就需要重新登錄。
本案例工程使用maven進(jìn)行構(gòu)建,使用SpringMVC、Servlet3.0實(shí)現(xiàn)。
- 導(dǎo)入spring-webmvc,javax.servlet-api依賴(lài)
<!--打成war可運(yùn)行在tomcat中-->
<packaging>war</packaging>
<!-- 設(shè)置jdk1.8編譯 -->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<!-- webmvc依賴(lài) servlet依賴(lài) -->
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<hostName>localhost</hostName> <!-- Default: localhost -->
<port>8080</port> <!-- 啟動(dòng)端口 Default:8080 -->
<path>/</path> <!-- 訪問(wèn)應(yīng)用路徑 Default: /${project.artifactId}-->
<uriEncoding>UTF-8</uriEncoding> <!-- uri編碼 Default: ISO-8859-1 -->
</configuration>
</plugin>
</plugins>
</build>
- 定義spring容器配置類(lèi)
//spring容器配置 相當(dāng)于applicationContext.xml
@Configuration
//組件掃描springmvc包 排除controller包
@ComponentScan(basePackages = "com.gyf.security.springmvc"
,excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,value = Controller.class)})
public class ApplicationConfig {
//將配置文件中的配置拿到類(lèi)中來(lái)配置
//配置除了Controller的其他bean,如數(shù)據(jù)庫(kù)連接池,事務(wù)管理器,業(yè)務(wù)bean等
}
- 定義springmvc配置類(lèi)
//servletContext配置 /相當(dāng)于springvc.xml文件
//該類(lèi)實(shí)現(xiàn)WebMvcConfigurer接口進(jìn)行配置
//組件掃描springmvc包,包含Controller包
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.gyf.security.springmvc"
,includeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION,value = Controller.class))
public class WebConfig implements WebMvcConfigurer {
//視圖解析器
@Bean
public InternalResourceViewResolver viewResolver(){
InternalResourceViewResolver internalResourceViewResolver = new InternalResourceViewResolver();
internalResourceViewResolver.setPrefix("/WEB-INF/view/");
internalResourceViewResolver.setSuffix(".jsp");
return internalResourceViewResolver;
}
//添加視圖控制器
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("login");
}
@Autowired
private SimpleAuthenticationInterceptor simpleAuthenticationInterceptor;
//添加攔截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
//對(duì)指定的url進(jìn)行攔截
registry.addInterceptor(simpleAuthenticationInterceptor).addPathPatterns("/r/**");
}
}
- 手動(dòng)加載spring配置文件
//手動(dòng)加載spring配置類(lèi)
//該類(lèi)繼承AbstractAnnotationConfigDispatcherServletInitializer,此類(lèi)實(shí)現(xiàn)WebApplicationInitializer接口,Spring容器啟動(dòng)時(shí)加載WebApplicationInitializer接口的所有實(shí)現(xiàn)類(lèi)
public class SpringApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
//加載spring容器 加載ApplicationContext.xml
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{ApplicationConfig.class};
}
//servletContext 加載springmvc.xml
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{WebConfig.class};
}
//url-mapping
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
- 自定義認(rèn)證頁(yè)面 lgoin.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="utf-8" %>
<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>
- 創(chuàng)建兩個(gè)實(shí)體類(lèi) UserDto,AuthenticationRequest并添加get、set方法,構(gòu)造方法
//用戶表
public class AuthenticationRequest {
//用戶名
private String username;
//密碼
private String password;
}
//用戶具體信息表
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;
/**
* 用戶的權(quán)限
*/
private Set<String> authorities;
}
- 業(yè)務(wù)層Service 自定義認(rèn)證服務(wù)用于用戶的身份認(rèn)證
public interface AuthenticationService {
//用戶認(rèn)證
UserDto authentication(AuthenticationRequest request);
}
@Service
public class AuthenticationServiceImpl implements AuthenticationService {
/**
* 用戶認(rèn)證
* @param request
* @return
*/
@Override
public UserDto authentication(AuthenticationRequest request) {
//校驗(yàn)參數(shù)是否為空
if (request==null || StringUtils.isEmpty(request.getUsername()) || StringUtils.isEmpty(request.getPassword())){
throw new RuntimeException("賬號(hào)或密碼為空");
}
//根據(jù)用戶和密碼去查詢數(shù)據(jù)庫(kù) 模擬數(shù)據(jù)庫(kù)
UserDto userDto = this.getUserDto(request.getUsername());
//判斷用戶是否為空
if (userDto==null){
throw new RuntimeException("查詢不到該用戶");
}
//校驗(yàn)密碼
if (!request.getPassword().equals(userDto.getPassword())){
throw new RuntimeException("密碼錯(cuò)誤");
}
//認(rèn)證通過(guò) 返回用戶的身份信息
return userDto;
}
//用戶信息 假裝到數(shù)據(jù)庫(kù)獲取數(shù)據(jù)
private Map<String,UserDto> map = new HashMap<>();
//代碼塊
{
Set<String> authorities1 = new HashSet<>();
authorities1.add("p1");
Set<String> authorities2 = new HashSet<>();
authorities2.add("p2");
map.put("zhangsan",new UserDto("1010","zhangsan","123456","張三","123456",authorities1));
map.put("lisi",new UserDto("1001","lisi","123","李四","789456",authorities2));
}
//根據(jù)賬號(hào)查詢用戶信息
private UserDto getUserDto(String username){
UserDto userDto = map.get(username);
return userDto;
}
}
- 表現(xiàn)層Controller 僅測(cè)試用
//@Controller+@ResponseBody
@RestController
public class LoginController {
@Autowired
private AuthenticationService authenticationService;
//produces 存文本類(lèi)型
@RequestMapping(value = "/login",produces = "text/plain;charset=utf-8")
public String login(AuthenticationRequest request, HttpSession httpSession){
UserDto userDto = authenticationService.authentication(request);
//將用戶信息存入session
httpSession.setAttribute(UserDto.SESSION_USER_KEY,userDto);
return userDto.getUsername()+"登陸成功";
}
/**
* 刪除session中的數(shù)據(jù)
* @param session
* @return
*/
@GetMapping(value = "/logout",produces = "text/plain;charset=utf-8")
public String logout(HttpSession session){
//刪除session中的數(shù)據(jù)
session.invalidate();
return "退出成功";
}
/**
* 判斷session中是否有數(shù)據(jù)
* @param session
* @return
*/
@GetMapping(value = "/r/r1",produces = "text/plain;charset=utf-8")
public String r1(HttpSession session){
String fullname = null;
//到session中獲取數(shù)據(jù)
Object attribute = session.getAttribute(UserDto.SESSION_USER_KEY);
if (attribute==null){
fullname="匿名";
}else {
fullname=((UserDto)attribute).getFullname();
}
return fullname+"訪問(wèn)r1";
}
@GetMapping(value = "/r/r2",produces = "text/plain;charset=utf-8")
public String r2(HttpSession session){
String fullname = null;
//到session中獲取數(shù)據(jù)
Object attribute = session.getAttribute(UserDto.SESSION_USER_KEY);
if (attribute==null){
fullname="匿名";
}else {
fullname=((UserDto)attribute).getFullname();
}
return fullname+"訪問(wèn)r2";
}
}
- 自定義攔截器 用于用戶的授權(quán)
//spring中的組件
@Component
//實(shí)現(xiàn) HandlerInterceptor接口
public class SimpleAuthenticationInterceptor implements HandlerInterceptor {
//校驗(yàn)用戶請(qǐng)求的url是否在用戶的權(quán)限范圍內(nèi)
//preHandle方法是在調(diào)用方法之前來(lái)調(diào)用這個(gè)方法
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
/**
* 校驗(yàn)用戶請(qǐng)求的url是否有權(quán)限訪問(wèn)
*/
//獲取session中的用戶信息
Object attribute = request.getSession().getAttribute(UserDto.SESSION_USER_KEY);
//校驗(yàn)是否登錄
if (attribute==null){//代表session沒(méi)有信息 提示登錄
writContext(response,"請(qǐng)登錄");
return false;
}
UserDto userDto = (UserDto) attribute;
//獲取請(qǐng)求url
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;
}
writContext(response,"沒(méi)有權(quán)限訪問(wèn)");
return false;
}
//響應(yīng)信息給前端
private void writContext(HttpServletResponse response, String msg) throws IOException {
//誰(shuí)知響應(yīng)格式
response.setContentType("text/application;charset=utf-8");
PrintWriter writer = response.getWriter();
//向前端返回?cái)?shù)據(jù)
writer.print(msg);
writer.close();
}
}