您好,登錄后才能下訂單哦!
下面來通過一個實例講解Session認證的方式
創(chuàng)建工程:
引入依賴:
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.0.4.RELEASE</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.8</version> </dependency> </dependencies> <build> <finalName>security‐springmvc</finalName> <pluginManagement> <plugins> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7‐maven‐plugin</artifactId> <version>2.2</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven‐compiler‐plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </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> </plugin> </plugins> </pluginManagement> </build>
Spring容器配置
在config包下定義ApplicationConfig.java,這個配置類相當于spring的配置文件
@Configuration
@ComponentScan(basePackages = ,excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,value = Controller.)})ApplicationConfig { }
在config包下定義WebConfig.java,這個配置類相當于springmv的配置文件
@Configuration @EnableWebMvc @ComponentScan(basePackages = "cn.xh" ,includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,value = Controller.class)})public class WebConfig implements WebMvcConfigurer { //視頻解析器 @Bean public InternalResourceViewResolver viewResolver(){ InternalResourceViewResolver viewResolver = new InternalResourceViewResolver(); viewResolver.setPrefix("/WEB-INF/view/"); viewResolver.setSuffix(".jsp"); return viewResolver; } }
加載spring容器
在init包下定義spring容器的初始化類SpringApplicationInitializer,該類實現(xiàn)了WebApplicationInitializer接口相當于web.xml文件。Spring容器啟動時會加載所有實現(xiàn)了WebApplicationInitializer接口的類。
public class SpringApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return new Class<?>[] { ApplicationConfig.class }; } @ Override protected Class<?>[] getServletConfigClasses() { return new Class<?>[] { WebConfig.class }; } @ Override protected String[] getServletMappings() { return new String [] {"/"}; } }
該類對應的web.xml文件可以參考:
<web‐app>
<listener>
<listener‐class>org.springframework.web.context.ContextLoaderListener</listener‐class>
</listener>
<context‐param>
<param‐name>contextConfigLocation</param‐name>
<param‐value>/WEB‐INF/application‐context.xml</param‐value>
</context‐param>
<servlet>
<servlet‐name>springmvc</servlet‐name>
<servletclass>org.springframework.web.servlet.DispatcherServlet</servlet‐class>
<init‐param>
<param‐name>contextConfigLocation</param‐name>
<param‐value>/WEB‐INF/spring‐mvc.xml</param‐value>
</init‐param>
<load‐on‐startup>1</load‐on‐startup>
</servlet>
<servlet‐mapping>
<servlet‐name>springmvc</servlet‐name>
<url‐pattern>/</url‐pattern>
</servlet‐mapping>
</web‐app>
實現(xiàn)認證功能
在webapp/WEB-INF/views下定義認證頁面login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<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>
在WebConfig中新增如下配置,將/直接導向login.jsp頁面:
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("login");
}
啟動項目,訪問/路徑地址,進行測試
創(chuàng)建認證接口;
認證接口用來對傳入的用戶名和密碼進行驗證,驗證成功返回用戶的詳細信息,失敗拋出錯誤異常。
public interface AuthenticationService {
/**
* 用戶認證
* @param authenticationRequest 用戶認證請求
* @return 認證成功的用戶信息
*/
UserDto authentication(AuthenticationRequest authenticationRequest);
}
認證請求結構:
@Data
public class AuthenticationRequest {
/**
* 用戶名
*/
private String username;
/**
* 密碼
*/
private String password;
}
用戶詳細信息:
@Data
@AllArgsConstructor
public class UserDto {
private String id;
private String username;
private String password;
private String fullname;
private String mobile;
}
認證實現(xiàn)類:
@Service
public class AuthenticationServiceImpl implements AuthenticationService {
@Override
public UserDto authentication(AuthenticationRequest authenticationRequest) {
if(authenticationRequest == null
|| StringUtils.isEmpty(authenticationRequest.getUsername())
|| StringUtils.isEmpty(authenticationRequest.getPassword())){
throw new RuntimeException("賬號或密碼為空");
}
UserDto userDto = getUserDto(authenticationRequest.getUsername());
if(userDto == null){
throw new RuntimeException("查詢不到該用戶");
}
if(!authenticationRequest.getPassword().equals(userDto.getPassword())){
throw new RuntimeException("賬號或密碼錯誤");
}
return userDto;
}
//模擬用戶查詢
public UserDto getUserDto(String username){
return userMap.get(username);
}
//用戶信息
private Map<String,UserDto> userMap = new HashMap<>();
{
userMap.put("zhangsan",new UserDto("1010","zhangsan","123","張三","133443"));
userMap.put("lisi",new UserDto("1011","lisi","456","李四","144553"));
}
}
登錄controller:
@RestController
public class LoginController {
@Autowired
private AuthenticationService authenticationService;
/**
* 用戶登錄
* @param authenticationRequest 登錄請求
* @return
*/
@PostMapping(value = "/login",produces = "text/plain;charset=utf‐8")
public String login(AuthenticationRequest authenticationRequest){
UserDto userDto = authenticationService.authentication(authenticationRequest);
return userDto.getFullname() + " 登錄成功";
}
}
測試
實現(xiàn)會話功能:
當用戶登錄系統(tǒng)后,系統(tǒng)需要記住用戶的信息,一般會把用戶的信息放在session中,在需要的時候從session中獲取用戶的信息,這就是會話機制。
首先在UserDto中定義一個Session_USER_KEY,作為session的key
public static final String SESSION_USER_KEY = "_user";
修改LoginController,認證成功后,將用戶的信息放入session,并增加用戶注銷的方法,用戶注銷時清空session
@PostMapping(value = "/login",produces = "text/plain;charset=utf‐8")
public String login(AuthenticationRequest authenticationRequest, HttpSession session){
UserDto userDto = authenticationService.authentication(authenticationRequest);
//用戶信息存入session
session.setAttribute(UserDto.SESSION_USER_KEY,userDto);
return userDto.getUsername() + "登錄成功";
}
@GetMapping(value = "logout",produces = "text/plain;charset=utf‐8")
public String logout(HttpSession session){
session.invalidate();
return "退出成功";
}
增加測試資源,在LoginController中增加測試資源:
@GetMapping(value = "/r/r1",produces = {"text/plain;charset=utf-8"})
public String r1(HttpSession session){
String fullname = null;
Object userObj = session.getAttribute(UserDto.SESSION_USER_KEY);
if(userObj != null){
fullname = ((UserDto)userObj).getFullname();
}else{
fullname = "匿名";
}
return fullname + " 訪問資源1";
}
測試:
未登錄訪問 /r/r1顯示:
已登錄訪問 /r/r1顯示:
實現(xiàn)授權功能
用戶訪問系統(tǒng)需要經過授權,需要完成如下功能:
禁止未登錄用戶訪問某些資源
登錄用戶根據(jù)用戶的權限決定是否能訪問某些資源
第一步:在UserDto里增加權限屬性表示該登錄用戶擁有的權限:
@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;
}
第二步:在AuthenticationServiceImpl中為用戶初始化權限,張三給了p1權限,李四給了p2權限:
//用戶信息
private Map<String,UserDto> userMap = new HashMap<>();
{
Set<String> authorities1 = new HashSet<>();
authorities1.add("p1");
Set<String> authorities2 = new HashSet<>();
authorities2.add("p2");
userMap.put("zhangsan",new UserDto("1010","zhangsan","123","張三","133443",authorities1));
userMap.put("lisi",new UserDto("1011","lisi","456","李四","144553",authorities2));
}
第三步:在LoginController中增加測試資源:
/**
* 測試資源2
* @param session
* @return
*/
@GetMapping(value = "/r/r2",produces = {"text/plain;charset=utf-8"})
public String r2(HttpSession session){
String fullname = null;
Object userObj = session.getAttribute(UserDto.SESSION_USER_KEY);
if(userObj != null){
fullname = ((UserDto)userObj).getFullname();
}else{
fullname = "匿名";
}
return fullname + " 訪問資源2";
}
第四步:在interceptor包下實現(xiàn)授權攔截器SimpleAuthenticationInterceptor:
校驗用戶是否登錄
校驗用戶是否有操作權限
@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 user = (UserDto) object;
//請求的url
String requestURI = request.getRequestURI();
if (user.getAuthorities().contains("p1") && requestURI.contains("/r1")) {
return true;
}
if (user.getAuthorities().contains("p2") && requestURI.contains("/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.print(msg);
writer.close();
response.resetBuffer();
}
}
在WebConfig中配置攔截器,配置/r/**的資源被攔截器處理:
@Autowired
private SimpleAuthenticationInterceptor simpleAuthenticationInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(simpleAuthenticationInterceptor).addPathPatterns("/r/**");
}
測試:
未登錄:
張三訪問/r/r1:
張三訪問 /r/r2:
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經查實,將立刻刪除涉嫌侵權內容。